Array initialization with default constructor
Asked Answered
H

6

21
public class Sample
{
     static int count = 0;
     public int abc;
     public Sample()
     {
        abc = ++Sample.count;
     }
}

I want to create an array of above class, and want each element in the array to be initialized by invoking the default constructor, so that each element can have different abc.So I did this:

Sample[] samples = new Sample[100];

But this doesn't do what I think it should do. It seems this way the default constructor is not getting called. How to invoke default constructor when creating an array?

I also would like to know what does the above statement do?

Harbison answered 29/1, 2011 at 21:15 Comment(6)
why don't you just use the array index, its unique and auto incremental as per your codeTaxdeductible
On a side note - that code is not thread-safe; you should use id = Interlocked.Increment(ref count) instead, and start with static int count = 1 (since Interlocked.Increment returns the old value).Antilebanon
well in the code above you just declared an array of size 100, there are no items in it.Inebriate
@Ivanov if he does that, when he pulls an item out of the array he wont have a unique identifier for the object.Inebriate
@Ivanov and @Victor: you guys have focused on id as if that is the point of the question. So I replaced id with abc.Harbison
Side not to side note: But if you are not using multiple threads - don't use Interlocked.Increment instead of ++.Riesling
U
48

You can't, basically. When you create an array, it's always initially populated with the default value for the type - which for a class is always a null reference. For int it's 0, for bool it's false, etc.

(If you use an array initializer, that will create the "empty" array and then populate it with the values you've specified, of course.)

There are various ways of populating the array by calling the constructor - I would probably just use a foreach loop myself. Using LINQ with Enumerable.Range/Repeat feels a little forced.

Of course, you could always write your own population method, even as an extension method:

public static T[] Populate<T>(this T[] array, Func<T> provider)
{
    for (int i = 0; i < array.Length; i++)
    {
        array[i] = provider();
    }
    return array;
}

Then you could use:

Sample[] samples = new Sample[100].Populate(() => new Sample());

What I like about this solution:

  • It's still a single expression, which can be useful in various scenarios
  • It doesn't introduce concepts you don't actually want (like repeating a single value or creating a range)

Of course you could add more options:

  • An overload which takes a Func<int, T> instead of a Func<T>, passing the index to the provider
  • A non-extension method which creates the array and populates it
Unbent answered 29/1, 2011 at 21:19 Comment(2)
I liked this solution most. :-) Reusable Method. :-)Harbison
Another useful overload is replace , Func<T> provider) with ) where T : new() and then you don't need to pass in a delegate at all if you are just using the default constructor (you will also need to replace provider() with new T()).Rozellarozelle
F
10

Your code creates only the array, but neither of its items. Basically, you need to store instances of Sample into this array.

To put it simple, without any fancy LINQ etc.:

Sample[] samples = new Sample[100];
for (int i = 0; i < samples.Length; i++) samples[i] = new Sample();

Please also note your solution is not thread-safe.

Farahfarand answered 29/1, 2011 at 21:19 Comment(0)
A
5

There is no way to do this automatically; array initialization is essentially "wipe this block of memory to 0s". You would have to do something like:

var arr = new SomeType[size];
for(int i = 0 ; i < size ; i++) arr[i] = new SomeType();
Antilebanon answered 29/1, 2011 at 21:18 Comment(0)
H
2

The problem is that by declaring that array, you never allocated space for each object. You merely allocated space for 100 objects of type Sample. You'll have to call the constructor on each yourself.

To elaborate:

Food[] foods = Food[100];
for (int k = 0; k < foods.length; k++) {
   foods[k] = new Food();
}

An interesting work around might be a factory function. Consider attaching this to your Sample class.

public static Sample[] getInstances(int aNumber) {
    Sample[] sample = Sample[aNumber];
    for (int k = 0; k < sample.length; k++) {
       sample[k] = new Sample();
    }

    return sample;
}

Hides the blemish, a bit - providing this is a useful function to you.

Hypochondriasis answered 29/1, 2011 at 21:19 Comment(2)
I edited it with a solution you might like. Short answer is yes, though. :/Hypochondriasis
You're creating array of Food but the return type is Sample[] :PHarbison
I
2

At this point you have an empty array of size 100, if you want to fill it with items, then you would have to do something like:

for(int i=0; i<samples.Length; i++) {
   samples[i] = new Sample();
}
Inebriate answered 29/1, 2011 at 21:24 Comment(0)
E
2

Here is another one-liner that doesn't require any extension method:

Sample[] array = Enumerable.Range(0, 100).Select(i => new Sample()).ToArray();

Another nice option is Scott's suggestion to Jon's answer:

public static T[] Populate<T>(this T[] array) 
    where T : new()
{
    for (int i = 0; i < array.Length; i++)
        array[i] = new T();
    return array;
}

So you can do:

Sample[] array = new Sample[100].Populate();
Econometrics answered 10/7, 2014 at 8:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.