为什么我可以像 C # 中的数组一样初始化 List?

今天我惊讶地发现在 C # 中我可以做:

List<int> a = new List<int> { 1, 2, 3 };

为什么我能这么做?构造函数叫什么?我怎样才能在自己的课上做到这一点呢?我知道这是初始化数组的方法,但是数组是语言项,而 List 是简单的对象..。

24377 次浏览

中的集合初始值设定项语法的一部分。NET.您可以在创建的任何集合上使用此语法,只要:

  • 它实现 IEnumerable(最好是 IEnumerable<T>)

  • 它有一个名为 Add(...)的方法

缺省构造函数被调用,然后初始化器的每个成员都被调用 Add(...)

因此,这两个区块大致相同:

List<int> a = new List<int> { 1, 2, 3 };

还有

List<int> temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
List<int> a = temp;

如果需要,可以调用 可以的替代构造函数,例如防止在增长过程中使 List<T>过大,等等:

// Notice, calls the List constructor that takes an int arg
// for initial capacity, then Add()'s three items.
List<int> a = new List<int>(3) { 1, 2, 3, }

请注意,Add()方法不需要带一个项目,例如 Dictionary<TKey, TValue>Add()方法带两个项目:

var grades = new Dictionary<string, int>
{
{ "Suzy", 100 },
{ "David", 98 },
{ "Karen", 73 }
};

大致相同于:

var temp = new Dictionary<string, int>();
temp.Add("Suzy", 100);
temp.Add("David", 98);
temp.Add("Karen", 73);
var grades = temp;

因此,要将它添加到您自己的类中,您所需要做的就是实现 IEnumerable(同样,最好是 IEnumerable<T>)并创建一个或多个 Add()方法:

public class SomeCollection<T> : IEnumerable<T>
{
// implement Add() methods appropriate for your collection
public void Add(T item)
{
// your add logic
}


// implement your enumerators for IEnumerable<T> (and IEnumerable)
public IEnumerator<T> GetEnumerator()
{
// your implementation
}


IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}

然后你可以像 BCL 集合那样使用它:

public class MyProgram
{
private SomeCollection<int> _myCollection = new SomeCollection<int> { 13, 5, 7 };


// ...
}

(有关详细信息,请参阅 MSDN)

这就是所谓的 语法糖

List<T>是一个“简单”的类,但是编译器对它进行了特殊处理,以使您的生活更加轻松。

这就是所谓的 集合初始值设定项。您需要实现 IEnumerable<T>Add方法。

它的工作要感谢 集合初始值设定项,它基本上要求集合实现一个 Add 方法,这将为您完成工作。

根据 C # 版本3.0规范“应用集合初始值设定项的集合对象必须是实现 System 的类型。收款。只要一个 T 的普通 ICollection

然而,这些信息在撰写本文时似乎是不准确的; 请参阅下面评论中 Eric Lippert 的澄清。

关于集合初始化器的另一个很酷的事情是,您可以有多个 Add方法的重载,并且您可以在同一个初始化器中调用它们!例如:

public class MyCollection<T> : IEnumerable<T>
{
public void Add(T item, int number)
{


}
public void Add(T item, string text)
{


}
public bool Add(T item) //return type could be anything
{


}
}


var myCollection = new MyCollection<bool>
{
true,
{ false, 0 },
{ true, "" },
false
};

它调用正确的重载。另外,它只查找名为 Add的方法,返回类型可以是任何类型。

在一系列 Add()调用中转换类似数组的语法。

为了在一个更有趣的示例中看到这一点,请考虑下面的代码,在这段代码中,我做了两件有趣的事情,这两件事在 C # 中听起来首先是非法的: 1)设置只读属性,2)使用类似初始化器的数组设置列表。

public class MyClass
{
public MyClass()
{
_list = new List<string>();
}
private IList<string> _list;
public IList<string> MyList
{
get
{
return _list;
}
}
}
//In some other method
var sample = new MyClass
{
MyList = {"a", "b"}
};

虽然1) MyList 是只读的,2)我使用数组初始化器设置了一个列表,但是这段代码可以很好地工作。

这样做的原因是,在作为对象初始化程序一部分的代码中,编译器总是将任何类似于 {}的语法转换为一系列即使在只读字段上也完全合法的 Add()调用。