C# 3.5中的List<int>初始化

21

我可以像这样初始化一个List<int>new List<int>{1,2,3,4,5}。但是List<T>没有接受单个参数的构造函数。因此,我尝试通过调试器运行它,看起来它似乎在调用Add方法。那么编译器如何知道调用哪个方法来添加每个单独的元素呢?

这可能是一个愚蠢的问题,但我有点困惑。

谢谢

5个回答

10

这是一个集合初始化器,是 C# 3.0语言特性。它需要:

  • 该类型必须实现IEnumerable(尽管此特性在初始化中从未使用)
  • 该类型必须至少有一个Add方法

它只是为每个项调用Add方法。 如果Add接受多个值,例如字典,您还可以使用元组,每个项就是{key,value}

new Dictionary<int,string> {{1,"abc"},{2,"def"}};

这里有一个使用自定义类型的示例:

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(); }
}

9

看一下这个方法。

    public void CreateList()
    {
        List<int> list = new List<int> { 1, 2, 3, 4, 5 };
    }

编译完成后,MSIL看起来像这样...
.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

正如你所看到的,这只是一种语法糖,编译器将初始化替换为Add()的连续调用。


9

任何具有Add方法并实现IEnumerable接口的类型都可以用这种方式进行初始化。

编译器会将您的代码编译成使用此Add方法的形式。

在这里查看 此处


2
不太对 - 它还必须实现IEnumerable接口(Add方法必须有参数,且必须有可访问的构造函数)。 - Jon Skeet

5

new List{ 1, 2, 3, 4, 5 } 只是语法糖。在底层,它只是为每个项调用了 Add 方法。


哼,没有人承认对正确答案进行了负评。实行民主啊! - Mitch Wheat

0

由于new List<int>{1,2,3,4,5}是数组初始化,我更喜欢认为它通过魔法在内部处理,因为我无法影响它发生的方式。想一想,它可能在元数据中定义了向集合添加元素的默认方法,其中[]是按索引完成的,而实现IList的则使用Add方法。


这不是“数组初始化”-那是一个非常不同的话题。而且,正如它发生的那样,它也不依赖于IList.Add(但这是一个合理的推测)。 - Marc Gravell
我的意思是集合初始化,这对OP可能有所帮助。 - Bablo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接