I can initialize a List<int> like new List<int>{1,2,3,4,5};
However List<T>
does not have a constructor which accepts a si开发者_运维问答ngle parameter.
So I tried to run this through the debugger and it seems to be calling the Add method.
So how does the compiler know which method to invoke to add each individual element.
This may be a silly question but I am a bit confused.
Thanks
This is a collection initializer, a C# 3.0 language feature. It requires:
- the type must implement
IEnumerable
(although this is never used for initialization) - the type must have at least one
Add
method
It simply calls the Add
method for each term.
You can also use tuples if the Add
accepts multiple values, for example dictionaries. Each term is then {key,value}
:
new Dictionary<int,string> {{1,"abc"},{2,"def"}};
For an example of using this for a bespoke type:
class Program
{
static void Main()
{
new Foo { 1, "abc", { 2, "def" } };
}
}
class Foo : IEnumerable
{
public void Add(int a) { }
public void Add(string b) { }
public void Add(int a, string b) { }
// must implement this!! (but never called)
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
}
Every type that has the method Add and implements IEnumerable can be initialized this way. The compiler just compiles your code as if you used this Add method.
take a look here
Look at this method.
public void CreateList()
{
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
}
After compiling this, the MSIL looks like this..
.method public hidebysig instance void CreateList() cil managed
{
// Code size 50 (0x32)
.maxstack 2
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> list,
[1] class [mscorlib]System.Collections.Generic.List`1<int32> '<>g__initLocal0')
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: ldc.i4.1
IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_000e: nop
IL_000f: ldloc.1
IL_0010: ldc.i4.2
IL_0011: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_0016: nop
IL_0017: ldloc.1
IL_0018: ldc.i4.3
IL_0019: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_001e: nop
IL_001f: ldloc.1
IL_0020: ldc.i4.4
IL_0021: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_0026: nop
IL_0027: ldloc.1
IL_0028: ldc.i4.5
IL_0029: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_002e: nop
IL_002f: ldloc.1
IL_0030: stloc.0
IL_0031: ret
} // end of method Program::CreateList
As you can observe, It's just a syntactic sugar and the compiler replaces the intialization by consecutive calls of Add().
new List{ 1, 2, 3, 4, 5 }
is just syntactic 'sugar'. Under the covers it will simply call the Add
method for each item.
As new List<int>{1,2,3,4,5}
is array initialization, i prefer to think it works this out internally by magic since i can't effect the way it happens. Coming to think of it, it probably defines the default method for adding elements to the collection in metadata where []
is done by index and those that implement IList
are done by the Add
method.
精彩评论