IDictionary分配快捷方式是编译器功能还是语言功能?

4
今天在创建一些随机对象时,我发现了一个很棒的 Dictionary<K, V> 的小快捷方式。以下赋值是编译器的快捷方式还是Dictionary<string, string>的特性呢?
IDictionary<string, string> items = { { "item1key", "item1value" } };

查看Dictionary<K, V>的源代码,我没有看到任何关于它如何工作的信息。实现该类的所有接口并不能让我执行类似的操作。为什么我们可以在字典中这样做,而不是其他类型呢?例如,编译器或语言特性如何知道第一个项目是键,第二个项目是值。或者更具体地说,这种相同的语法不能用于List<string>

List<string> items = { "item1" };

所以第一个是有效的,为什么呢?

我并不是试图复制它,而是对它的方式感到好奇。什么使得这种情况下的字典特殊?

有效的示例

public class Button
{
    public string Title { get; set; }
    public ButtonType Type { get; set; }
    public IDictionary<string, string> Items { get; set; }
    public bool RequiresSelected { get; set; }
}

var buttons = new List<Button>
    {
        new Button { 
            Items = {
                        {"button1", "Button 1"},
                        {"button2", "Button 2"},
                        {"button3", "Button 3"},
                    }, 
            Title = "3 Buttons", 
            Type = ButtonType.DropDown 
        }
    };
2个回答

7

你展示的语法在C#中是无效的。正确的语法应该是:

IDictionary<string, string> items = new Dictionary<string, string>
    { { "item1key", "item1value" } };

在那个点上,它只是一个普通的集合初始化器,因此列表等价物将是:

List<string> items = new List<string> { "item1" };

编辑:让我们看看我的编辑是否比您的更好。我猜您可能已经见过类似于以下内容:

var foo = new Foo {
    SomeDictionaryProperty = { 
         { "item1key", "item1value" }
    }
};

这是一个嵌套的集合初始化器,也可以用于列表。它不是创建一个新的字典,而是添加到现有的字典中。上面的代码等价于:

var tmp = new Foo();
tmp.SomeDictionaryProperty.Add("item1key", "item1value");
var foo = tmp;

另一个示例展示其工作原理:
var form = new Form {
    Controls = { new Label { Text = "Foo"}, new Label { Text = "Bar" } }
};

请参阅C# 4规范(对象初始化程序)的第7.6.10.2节,以获取更多信息。重要的部分是这样的:
member-initializer:
    identifier   =   initializer-value

initializer-value:
    expression
    object-or-collection-initializer

所以您可以将属性初始化为特定值(在这种情况下,将使用setter),或通过对象/集合初始化程序进行初始化,在这种情况下,将使用属性的getter,然后将使用setter或Add方法来处理对象/集合初始化程序的主体。


啊,有趣。像我的例子一样内联不编译 - 让我放上我的实际用法。 - Buildstarted
@BuildStarted: 在我的电脑上不行,即使使用VS11 beta编译器也不行。请展示一个简短但是完整的程序,证明它可以运行。 - Jon Skeet
@BuildStarted:已经编辑了我的帖子,并猜测你正在做什么 :) - Jon Skeet
好的,如果我使用列表类型并以与字典相同的方式使用它,则它将起作用。因此,这是编译器的快捷方式,而不一定是语言本身的功能来简化赋值。 - Buildstarted
1
@BuildStarted: 这绝对是语言的一个特性。编译器只是在实现语言!如果你的意思是这不是.NET平台的一个特性,那么它就不是。很少有东西是编译器特性而不是语言特性 - 大多数都围绕着优化、警告等方面。 - Jon Skeet
我应该知道永远不要质疑你的答案 :) 谢谢 - Buildstarted

2
这是C#编译器的一个特性,字典并不是特殊的,任何支持Add的集合都可以用这种方式进行初始化。具体细节请参见C# Language Specification 4.0的第7.6.10.3节。
应用了集合初始化器的集合对象必须是实现System.Collections.IEnumerable接口的类型,否则将会出现编译错误。对于每个指定的元素,集合初始化器将使用元素初始化器的表达式列表作为参数列表,在目标对象上调用Add方法,并针对每个调用应用普通的重载决议。因此,集合对象必须包含每个元素初始化器都适用的Add方法。

感谢语言规范中提供的有用信息,说明了满足此要求所需的必要条件。这对我理解很有帮助。 - Buildstarted

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