C# 6.0 的新字典初始化器 - 说明
C# 6.0's new Dictionary Initializer - Clarification
我读过:
The team have generally been busy implementing other variations on
initializers. For example you can now initialize a Dictionary object
但是看着:
var Dic = new Dictionary<string,int>{ {"x",3}, {"y",7} };
对比
var Dic = new Dictionary<string,int>{ ["x"]=3, ["y"]=7 };
我看不出好处在哪里。它看起来一样。两者都不过是一个名称-值集合。
他们将成对的大括号换成成对的方括号和一些逗号
问题:
使用新语法的附加价值是什么?一个真实世界的例子将不胜感激。
第一种情况的代码使用集合初始化语法。为了能够使用集合初始化器语法,class 必须:
- 实现
IEnumerable
接口。
- 定义可访问的
Add()
方法。 (从C#6/VS2015开始,可能是一种扩展方法)
所以像这样定义的 class 可以使用语法:
public class CollectionInitializable : IEnumerable
{
public void Add(int value) { ... }
public void Add(string key, int value) { ... }
public IEnumerator GetEnumerator() { ... }
}
var obj = new CollectionInitializable
{
1,
{ "two", 3 },
};
并非所有对象都是 IEnumerable
或具有添加方法,因此不能使用该语法。
另一方面,许多对象定义(可设置的)索引器。这是使用字典初始化程序的地方。拥有索引器可能有意义,但不一定是 IEnumerable
。有了字典初始化器,你不需要IEnumerable
,你不需要Add()
方法,你只需要一个索引器。
能够在单个表达式中完全初始化一个对象通常很有用(在某些情况下,这是一项要求)。字典初始化器语法使它更容易做到这一点,而无需使用集合初始化器的严格要求。
字典的主要优点是一致性。使用字典,初始化与使用看起来不一样。
例如,您可以这样做:
var dict = new Dictionary<int,string>();
dict[3] = "foo";
dict[42] = "bar";
但是使用初始化语法,你必须使用大括号:
var dict = new Dictionary<int,string>
{
{3, "foo"},
{42, "bar"}
};
新的 C#6 索引初始化语法使初始化语法与索引用法更加一致:
var dict = new Dictionary<int,string>
{
[3] = "foo",
[42] = "bar"
};
然而,更大的优势是这种语法还提供了允许您初始化其他类型的好处。任何具有索引器的类型都将允许通过此语法进行初始化,其中旧的集合初始化器仅适用于实现 IEnumerable<T>
并具有 Add
方法的类型。这恰好适用于 Dictionary<TKey,TValue>
,但这并不意味着它适用于任何基于索引的类型。
本身没有技术优势;它只是语法糖(就像许多新的 C# 6 功能一样)。而C# feature descriptions PDF,其实只提了一个文雅的问题:
Object and collection initializers are useful for declaratively initializing fields and properties of objects, or giving a collection an initial set of elements. Initializing dictionaries and other objects with indexers is less elegant. We are adding a new syntax to object initializers allowing you to set values to keys through any indexer that the new object has
这可能是一个有问题的功能,但新语法允许您多次设置相同的内容。
private static Dictionary<string, string> test1
= new Dictionary<string, string>() {
["a"] = "b",
["a"] = "c"
};
是允许的:这里键 "a"
的值为 "c"
.
相反,使用
private static Dictionary<string, string> test2
= new Dictionary<string, string>() {
{ "a","b" },
{ "a","c" },
};
创建异常:
Unbehandelte Ausnahme: System.TypeInitializationException: Der Typeninitialisierer für "ConsoleApplication1.Program" hat eine Ausnahme verursacht.
---> System.ArgumentException: Ein Element mit dem gleichen Schlüssel wurde bereits hinzugefügt.
bei System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
bei System.Collections.Generic.Dictionary``2.Insert(TKey key, TValue value, Boolean add)
bei System.Collections.Generic.Dictionary``2.Add(TKey key, TValue value)
bei ConsoleApplication1.Program..cctor() in Program.cs:Zeile 19.
--- Ende der internen Ausnahmestapelüberwachung ---
bei ConsoleApplication1.Program.Main(String[] args)
我读过:
The team have generally been busy implementing other variations on initializers. For example you can now initialize a Dictionary object
但是看着:
var Dic = new Dictionary<string,int>{ {"x",3}, {"y",7} };
对比
var Dic = new Dictionary<string,int>{ ["x"]=3, ["y"]=7 };
我看不出好处在哪里。它看起来一样。两者都不过是一个名称-值集合。
他们将成对的大括号换成成对的方括号和一些逗号
问题:
使用新语法的附加价值是什么?一个真实世界的例子将不胜感激。
第一种情况的代码使用集合初始化语法。为了能够使用集合初始化器语法,class 必须:
- 实现
IEnumerable
接口。 - 定义可访问的
Add()
方法。 (从C#6/VS2015开始,可能是一种扩展方法)
所以像这样定义的 class 可以使用语法:
public class CollectionInitializable : IEnumerable
{
public void Add(int value) { ... }
public void Add(string key, int value) { ... }
public IEnumerator GetEnumerator() { ... }
}
var obj = new CollectionInitializable
{
1,
{ "two", 3 },
};
并非所有对象都是 IEnumerable
或具有添加方法,因此不能使用该语法。
另一方面,许多对象定义(可设置的)索引器。这是使用字典初始化程序的地方。拥有索引器可能有意义,但不一定是 IEnumerable
。有了字典初始化器,你不需要IEnumerable
,你不需要Add()
方法,你只需要一个索引器。
能够在单个表达式中完全初始化一个对象通常很有用(在某些情况下,这是一项要求)。字典初始化器语法使它更容易做到这一点,而无需使用集合初始化器的严格要求。
字典的主要优点是一致性。使用字典,初始化与使用看起来不一样。
例如,您可以这样做:
var dict = new Dictionary<int,string>();
dict[3] = "foo";
dict[42] = "bar";
但是使用初始化语法,你必须使用大括号:
var dict = new Dictionary<int,string>
{
{3, "foo"},
{42, "bar"}
};
新的 C#6 索引初始化语法使初始化语法与索引用法更加一致:
var dict = new Dictionary<int,string>
{
[3] = "foo",
[42] = "bar"
};
然而,更大的优势是这种语法还提供了允许您初始化其他类型的好处。任何具有索引器的类型都将允许通过此语法进行初始化,其中旧的集合初始化器仅适用于实现 IEnumerable<T>
并具有 Add
方法的类型。这恰好适用于 Dictionary<TKey,TValue>
,但这并不意味着它适用于任何基于索引的类型。
本身没有技术优势;它只是语法糖(就像许多新的 C# 6 功能一样)。而C# feature descriptions PDF,其实只提了一个文雅的问题:
Object and collection initializers are useful for declaratively initializing fields and properties of objects, or giving a collection an initial set of elements. Initializing dictionaries and other objects with indexers is less elegant. We are adding a new syntax to object initializers allowing you to set values to keys through any indexer that the new object has
这可能是一个有问题的功能,但新语法允许您多次设置相同的内容。
private static Dictionary<string, string> test1
= new Dictionary<string, string>() {
["a"] = "b",
["a"] = "c"
};
是允许的:这里键 "a"
的值为 "c"
.
相反,使用
private static Dictionary<string, string> test2
= new Dictionary<string, string>() {
{ "a","b" },
{ "a","c" },
};
创建异常:
Unbehandelte Ausnahme: System.TypeInitializationException: Der Typeninitialisierer für "ConsoleApplication1.Program" hat eine Ausnahme verursacht.
---> System.ArgumentException: Ein Element mit dem gleichen Schlüssel wurde bereits hinzugefügt.
bei System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
bei System.Collections.Generic.Dictionary``2.Insert(TKey key, TValue value, Boolean add)
bei System.Collections.Generic.Dictionary``2.Add(TKey key, TValue value)
bei ConsoleApplication1.Program..cctor() in Program.cs:Zeile 19.
--- Ende der internen Ausnahmestapelüberwachung ---
bei ConsoleApplication1.Program.Main(String[] args)