views:

3159

answers:

7

In C# I can initialize a list using the following syntax.

List<int> intList= new List<int>() { 1, 2, 3 };

I would like to how that {} syntax works, and if it has a name. There is a constructor that takes an Ienumerable, you could call that.

List<int> intList= new List<int>(new int[]{ 1, 2, 3 });

That seems more "standard". When I deconstruct the default constructor for the List I only see

this._items = Array.Empty;

I would like to be able to do this.

CustomClass abc = new CustomClass() {1,2,3};

And be able to use the 1,2,3 list, how does this work?

Update

Jon Skeet answered

It's calling the parameterless constructor, and then calling Add:

> List<int> tmp = new List<int>();
> tmp.Add(1); tmp.Add(2); tmp.Add(3);
> List<int> intList = tmp;

I understand what is does. I want to know how. How does that syntax know to call the Add method?

Update

I know, how cliche to accept a Jon Skeet answer. But, the example with the strings and ints is awesome. Also two very helpful MSDN pages, http://msdn.microsoft.com/en-us/library/bb384062.aspx http://msdn.microsoft.com/en-us/library/bb384062.aspx

Thanks for all your answers!

+13  A: 

This is called a collection initializer. It's calling the parameterless constructor, and then calling Add:

List<int> tmp = new List<int>();
tmp.Add(1);
tmp.Add(2);
tmp.Add(3);
List<int> intList = tmp;

The requirements for the type are:

  • It implements IEnumerable
  • It has overloads of Add which are appropriate for the argument types you supply. You can supply multiple arguments in braces, in which case the compiler looks for an Add method with multiple parameters.

For example:

public class DummyCollection : IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new InvalidOperationException("Not a real collection!");
    }

    public void Add(string x)
    {
        Console.WriteLine("Called Add(string)");
    }

    public void Add(int x, int y)
    {
        Console.WriteLine("Called Add(int, int)");
    }
}

You can then use:

DummyCollection foo = new DummyCollection
{
    "Hi",
    "There",
    { 1, 2 }
};

(Of course, normally you'd want your collection to implement IEnumerable properly...)

Jon Skeet
Please see question update.
Anthony D
Please see my answer update ;)
Jon Skeet
Skeet, thanks skeet! The example with string and its is awesome!
Anthony D
Jon, are you ever NOT on SO.com?
Anthony D
Shame the arguments were the wrong way round - but fixed now :)
Jon Skeet
So why does it care that the type is enumerable? it doesn't seem to add anything other than making C# more aware of .NET, similar to IDisposable.. makes me wonder why foreach requires JUST a compat signature, and not interfaces.. I thought the idea was so C# wouldn't be specifically tied to a 'lang'
meandmycode
that's why we have Jon Skeet here. Great answer! Thank you!
Vimvq1987
@meandmycode: foreach isn't tied to IEnumerable because pre-generics there was no other way of exposing an iterator without boxing. With generics I'm sure it would have *just* relied on IEnumerable<T>. (Continued)
Jon Skeet
As for collection initializers requiring IEnumerable, it's a good indication that the type really *is* a collection type, rather than another type which just happens to have an Add method (e.g. DateTime.Add).
Jon Skeet
+1  A: 

I believe it's a shortcut to the .Add method. I've never tried to override it, though, so I don't know if it's possible.

Matt Grande
It is possible, try implementing an IDictionary
Jhonny D. Cano -Leftware-
+3  A: 

read here

Basically you could this with every custom type that is a list (implements IEnumerable)

Cornel
A: 

As far as i'm concerned, the addition of items via object initialization searches a method Add,

so, as List will have void Add(int), it will work.

For use it in your class, just add

class CustomClass { 
   public void Add(int num) {
      // your code here
   }
}

Your class should implement IEnumerable, as Hallgrim pointed out

Jhonny D. Cano -Leftware-
+2  A: 

They're called collection initializers (also see here), and the way they work is by looking for an Add() method that can do their bidding. It calls Add() for each of the integers you have in your curly braces.

The search for the Add() method is pure compiler magic. It's hardcoded to find a method of that name.

mquander
Not sure where you've got the word "default" from there - they're just "collection initializers".
Jon Skeet
Fair enough, I changed it.
mquander
A: 

The name you're loooking for is "Collection Initializer". It works under the hood by looking for a method named Add on the collection type and calling it for every value that you specify.

More details: http://msdn.microsoft.com/en-us/library/bb384062.aspx

JaredPar
A: 

It's actually using the .Add method. Meaning it's calling .Add for each item in the brackets inside of the constructor.

Alexander Kahoun