5

Given a class:

class clsPerson { public int x, y; }

Is there some way to create an array of these classes with each element initialized to a (default) constructed instance, without doing it manually in a for loop like:

clsPerson[] objArr = new clsPerson[1000];

for (int i = 0; i < 1000; ++i)
    objArr[i] = new clsPerson();

Can I shorten the declaration and instantiation of an array of N objects?

Scott Smith
  • 3,900
  • 2
  • 31
  • 63
mike00
  • 438
  • 1
  • 6
  • 17
  • 4
    Just curious: why name it `clsPerson` and not `Person`? It's obvious that it's a class - most things _are_ classes. – John Saunders Feb 17 '12 at 18:11
  • http://stackoverflow.com/a/1739047/932418 – L.B Feb 17 '12 at 18:19
  • i think i can (ashamedly) answer that. this was an old VB6 way of naming classes - not that i would know of course :-) – jim tollan Feb 17 '12 at 18:23
  • @jimtollan - I was just about to mention that that looks like a VB6 artifact that is dreadfully useless. – ChaosPandion Feb 17 '12 at 18:24
  • If I want to do something *some number of times*, I use a loop. Why do you want to avoid using a loop? It's like saying "I have to drill a hole, I have a drill, but how do I drill the hole *without* the drill?" You don't! Loops are for doing the same thing a bunch of times; you have something you want to do a bunch of times, so *use a loop*. – Eric Lippert Feb 17 '12 at 18:28
  • @EricLippert pls calm down, see comment for answer Reed Copsey. JohnSaunders Thanks, for your comment. – mike00 Feb 17 '12 at 18:54
  • 4
    @Maniekb: Reed's answer uses *three loops*. There's a loop in Range, there's a loop in Select, and there's a loop in ToArray. Which is two *more* loops than you need. If you're seeking to avoid loops then you have to avoid LINQ at all costs; it is nothing but loops. – Eric Lippert Feb 17 '12 at 18:59
  • @EricLippert how is it three loops in Reed's answer? With delayed execution, the enumerables returned by Range and Select won't be iterated until ToArray() is called; that's just once. – phoog Feb 17 '12 at 19:59
  • 1
    @phoog: A delayed-execution loop is still a loop. Look at it this way: suppose you wrote the code for Range, Select and ToArray right now. How many times would "for/foreach/while/etc" appear in the resulting code? I say that if "for" appears three times in the code then there are three loops in that code. – Eric Lippert Feb 17 '12 at 20:12
  • @EricLippert but considering that `Range` and `Select` are presumably iterator blocks, the compiler doesn't emit a loop, it emits a state machine that implements `IEnumerator`. So you really have one loop on an enumerator that wraps an inner enumerator. The additional complexity comes in delegating MoveNext and Current to the wrapped enumerator. Obviously please correct me if I've gotten it wrong. – phoog Feb 17 '12 at 22:06
  • 1
    @phoog: Sure. But that inner enumerator is nothing more than a bunch of conditional gotos that repeatedly branch back to the same place over and over again until a condition is met. That's how I would *define* a loop: a conditional goto that branches back to previously executed code until a condition is met. – Eric Lippert Feb 17 '12 at 22:54
  • @Eric Lippert: Why does it have to be conditional? What is `A: goto A;` if not a loop? Or does it have the empty conditional? – jason Feb 18 '12 at 00:03

3 Answers3

15

The constructor must be run for every item in the array in this scenario. Whether or not you use a loop, collection initializers or a helper method every element in the array must be visited.

If you're just looking for a handy syntax though you could use the following

public static T[] CreateArray<T>(int count) where T : new() {
  var array = new T[count];
  for (var i = 0; i < count; i++) {
    array[i] = new T();
  }
  return array;
}

clsPerson[] objArary = CreateArray<clsPerson>(1000);
Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
11

You must invoke the constructor for each item. There is no way to allocate an array and invoke your class constructors on the items without constructing each item.

You could shorten it (a tiny bit) from a loop using:

clsPerson[] objArr = Enumerable.Range(0, 1000).Select(i => new clsPerson()).ToArray();

Personally, I'd still allocate the array and loop through it (and/or move it into a helper routine), though, as it's very clear and still fairly simple:

clsPerson[] objArr = new clsPerson[1000];
for (int i=0;i<1000;++i) 
   clsPerson[i] = new clsPerson(); 
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Hmm, I know it's pretty simple, but i see many features like: List list = new List({1,2,3}); or foreach(string in new string[]{"aaa", "bbb"}) – mike00 Feb 17 '12 at 18:15
  • @Maniekb Well, as I said - you could use LINQ to do it, but I'd personally avoid it in this case... – Reed Copsey Feb 17 '12 at 18:17
  • @Maniekb But of course you could use array initializer syntax, if you feel like typing `new clsPerson()` 1000 times in the initializer. – phoog Feb 17 '12 at 18:30
0

If it would make sense to do so, you could change class clsPerson to struct Person. structs always have a default value.

Tim S.
  • 55,448
  • 7
  • 96
  • 122