C# 如何使内联数组初始化像字典初始化一样工作?

C# 如何使内联数组初始化像字典初始化一样工作?,c#,syntax,initialization,magic-methods,C#,Syntax,Initialization,Magic Methods,为什么可以像这样初始化词典: var dict = new Dictionary<string,int>() { { "key1", 1 }, { "key2", 2 } }; // Seriously! Don't do this in production code! Ever!!! public class CrazyAdd2 : IDictionary<string, int> { public int this[string key

为什么可以像这样初始化
词典

var dict = new Dictionary<string,int>() { 
    { "key1", 1 },
    { "key2", 2 }
};
// Seriously!  Don't do this in production code! Ever!!!
public class CrazyAdd2 : IDictionary<string, int>
{
    public int this[string key]
    {
        get { throw new NotImplementedException(); }
        set {Console.WriteLine($"([{key}]={value})"); }
    }

#region NotImplemented
// lots of empty methods go here
#endregion
}
var dict=new Dictionary(){
{“key1”,1},
{“key2”,2}
};
…但不是以完全相同的方式初始化
KeyValuePair
对象数组:

var kvps = new KeyValuePair<string,int>[] {
    { "key1", 1 },
    { "key2", 2 }
};
// compiler error: "Array initializers can only be used in a variable 
// or field initializer.  Try using a new expression instead."
var kvps=new KeyValuePair[]{
{“key1”,1},
{“key2”,2}
};
//编译器错误:“数组初始值设定项只能在变量中使用
//或字段初始值设定项。请尝试改用新表达式。“
我意识到我可以通过为每个项目编写
newkeyvaluepair(){“key1”,1}
等来实现第二个示例。但是我想知道是否可以使用第一个示例中可能使用的相同类型的简明语法


如果不可能,那么是什么使字典类型如此特殊?

您的问题源于它是一个数组,而不是集合

var kvps = new KeyValuePair<string,int>[] {
    { "key1", 1 },
    { "key2", 2 }
};
var kvps=new KeyValuePair[]{
{“key1”,1},
{“key2”,2}
};
应该是:

var kvps = new KeyValuePair<string, int>[] {
    new KeyValuePair<string, int>("key1", 1),
    new KeyValuePair<string, int>("key2", 2)
};
var kvps=new KeyValuePair[]{
新的KeyValuePair(“key1”,1),
新的KeyValuePair(“key2”,2)
};

赠品是括号<代码>[]是一个数组
{}
是一个集合。

集合初始值设定项语法被转换为调用
Add
,并使用适当数量的参数:

var kvps = new KeyValuePair<string,int>[] {
    { "key1", 1 },
    { "key2", 2 }
};
var dict = new Dictionary<string,int>();
dict.Add("key1", 1);
dict.Add("key2", 2);
现在你可以写下:

var crazyAdd = new CrazyAdd
{
    {1, 2, 3},
    {4, 5, 6}
};
产出:

6
15
在线查看它的工作情况:

至于你所问的其他类型:

  • 它不适用于数组,因为它没有
    Add
    方法
  • List
    有一个
    Add
    方法,但它只有一个参数

它确实适用于字典,因为它有一个包含两个参数的
Add
重载。数组甚至没有
Add
方法,更不用说有两个参数的方法了

Dictionary
类专门设计用于内部处理
KeyValuePair
,这是您不需要手动调用构造函数的唯一原因,而是调用两个参数
Add
,并在引擎盖下构造KeyValuePair

每隔一个
IEnumerable
没有此特殊实现,因此必须以以下方式初始化:

var array = new KeyValuePair<int, int>[] {
    new KeyValuePair<int, int>(1, 2),
    new KeyValuePair<int, int>(3, 4)
};
var数组=新的KeyValuePair[]{
新的KeyValuePair(1,2),
新的KeyValuePair(3,4)
};
您可以用自己的类创建相同的行为,比如说您实现了以下内容:

class ThreeTupleList<T1, T2, T3> : List<Tuple<T1, T2, T3>>
{
    public void Add(T1 a, T2 b, T3 c)
    {
        this.Add(new Tuple<T1, T2, T3>(a, b, c));
    }

    // You can even implement a two-argument Add and mix initializers
    public void Add(T1 a, T2 b)
    {
        this.Add(new Tuple<T1, T2, T3>(a, b, default(T3)));
    }
}
class三元组列表:列表
{
公共空间添加(T1 a、T2 b、T3 c)
{
添加(新元组(a,b,c));
}
//您甚至可以实现两个参数的Add和mix初始值设定项
公共空间添加(T1 a、T2 b)
{
Add(新元组(a,b,默认值(T3));
}
}
您可以这样初始化它,甚至可以混合使用三个、两个和一个参数的初始值设定项:

var mylist = new ThreeTupleList<int, string, double>()
{
    { 1, "foo", 2.3 },
    { 4, "bar", 5.6 },
    { 7, "no double here" },
    null
};
var mylist=新的三元组列表()
{
{1,“foo”,2.3},
{4,“酒吧”,5.6},
{7,“这里没有替身”},
无效的
};

您可能看不到它,但它的语法相同。唯一的区别是数组采用元素作为输入,而字典采用二维数组

int[] a = new int[]{5,6};
int[,] a = new int[]{{5,6},{3,6}};
Dictionary<int,int> a = new Dictionary<int,int>{{5,6},{3,6}};
int[]a=新的int[]{5,6};
int[,]a=新的int[]{{5,6},{3,6};
字典a=新字典{{5,6},{3,6};

多亏了众多回答者指出Add方法是使初始化语法起作用的神奇之物。因此,我可以通过继承所讨论的类(KeyValuePair)来实现我的目标:

公共类InitializableKVPs:IEnumerable
{
公共无效添加(T1键,T2值)
{
抛出新的NotImplementedException();
}
公共IEnumerator GetEnumerator()
{
抛出新的NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
抛出新的NotImplementedException();
}
}
编译器现在接受这一点:

var kvps = new InitializableKVPs<string,int> {
    { "key1", 1 },
    { "key2", 2 }
};
var kvps=new InitializableKVPs{
{“key1”,1},
{“key2”,2}
};
编辑:Philip Daubmeier的答案实际简洁地实现了这一点。

覆盖C#6.0语法的IDictionary 如果有人像我一样来到这里,希望为新的C#6.0字典初始值设定项语法保存一些击键,那么可以这样做,但需要从IDictionary派生。您只需要实现this[]set方法就可以让它工作,这会留下大量未实现的方法

类实现如下所示:

var dict = new Dictionary<string,int>() { 
    { "key1", 1 },
    { "key2", 2 }
};
// Seriously!  Don't do this in production code! Ever!!!
public class CrazyAdd2 : IDictionary<string, int>
{
    public int this[string key]
    {
        get { throw new NotImplementedException(); }
        set {Console.WriteLine($"([{key}]={value})"); }
    }

#region NotImplemented
// lots of empty methods go here
#endregion
}
以及输出:

([one]=1)
([two]=2)
这里有一把小提琴演示了整个过程:


也许我的问题没有表达清楚,但请仔细阅读。我在回答中提到了你的例子。我知道如何编写初始化,但我想知道为什么不能使用更简单的语法。好的。。。但List确实有一个add方法,尝试该方法会产生相同的错误。这是一个非常邪恶的add()。我喜欢这个问题,我喜欢这个问题的发展方向,但它似乎并不精确。我喜欢将重点放在
列表
字典
上的想法(以避开数组),尽管错误消息可能不同?(沉思:一个人如何知道如何从
{a,b}
?;-)创建KVP(尽管我认为我的标题不太正确。)@pst是的,我认为你越来越接近我要求的核心。我不太擅长写问题……这并不是为什么这种句法上的甜点是可能的。实际上,这是由于通用词典的实现,它提供了一个双参数
Add
,可在后台为您构建
KeyValuePair
。请参阅我的更新答案,了解这个非常简单的实现,如果您只是从已实现的
i集合
继承,例如,
列表
刚刚发现您甚至可以将初始值设定项元素与不同的