今天我惊奇地发现在C#中我可以这样做:
List<int> a = new List<int> { 1, 2, 3 };
我为什么可以这样做?调用了哪个构造函数?我如何使用自己的类来做到这一点?我知道这是初始化数组的方法,但数组是语言项,而列表是简单对象...
List<int> a = new List<int> { 1, 2, 3 };
我为什么可以这样做?调用了哪个构造函数?我如何使用自己的类来做到这一点?我知道这是初始化数组的方法,但数组是语言项,而列表是简单对象...
它实现了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();
}
}
public class MyProgram
{
private SomeCollection<int> _myCollection = new SomeCollection<int> { 13, 5, 7 };
// ...
}
List<int> temp = new List<int>(); temp.Add(1); ... List<int> a = temp;
完全相同,也就是说,在调用所有添加操作之后才会初始化a
变量。否则,就可以合法地做出像 List<int> a = new List<int>() { a.Count, a.Count, a.Count };
这样疯狂的事情了。 - Eric LippertList<int> a; a = new List<int>() { a.Count };
和List<int> a = new List<int>() { a.Count };
之间没有实质性的区别。 - JorenT x = y;
与T x; x = y;
是相同的。这个事实可能会导致一些奇怪的情况。例如,int x = M(out x) + x;
是完全合法的,因为int x; x = M(out x) + x;
是合法的。 - Eric Lippertusing (var x = new Something{ 1, 2 })
中的一个 Add
调用失败,那么对象不会被释放。 - porges集合初始化程序的另一个酷炫之处在于,您可以有多个 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()
调用,即使在只读字段上也是完全合法的。
{ { "key1", "value1"}, { "key2", "value2"} }
。 - danludwigList<int>
的底层数据类型实际上只是一个数组。我讨厌 C# 团队没有将其命名为ArrayList<T>
,这听起来是如此明显和自然的事情。 - RBT