【问题标题】:IDictionary assignment shortcuts compiler feature or language feature?字典赋值快捷方式编译器功能还是语言功能?
【发布时间】:2012-05-03 20:45:17
【问题描述】:

通过今天的一些随机对象创建,我发现了Dictionary<K, V> 的这个简洁的小快捷方式。以下分配是编译器快捷方式还是Dictionary<string, string> 的功能。

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

查看Dictionary&lt;K, V&gt; 的源代码我没有看到任何关于其工作原理的东西。为此类 dot 实现所有接口不允许我执行类似的操作。为什么我们可以为字典而不是另一种类型。例如,编译器或语言特性如何知道第一项是键,第二项是值。或者更具体地说,同样的语法不能用于List&lt;string&gt;

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 
        }
    };

【问题讨论】:

    标签: c# .net compiler-construction


    【解决方案1】:

    您显示的语法在 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" }
        }
    };
    

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

    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:在我的机器上没有,即使使用 VS11 beta 编译器也是如此。请展示一个适合您的简短但完整的程序。
    • @BuildStarted: 编辑了我的帖子,猜测你在做什么 :)
    • 好的,所以如果我以与使用字典相同的方式使用它,它将适用于列表类型。所以它是一个编译器快捷方式,不一定是语言本身的快捷方式分配功能。
    • @BuildStarted:这绝对是语言的一个特性。编译器只是实现语言!如果这就是您的意思,它本身不是 .NET 平台的功能。很少有东西是编译器特性而不是语言特性——主要是围绕优化、警告等。
    【解决方案2】:

    这是C#编译器的一个特性,字典并不特殊:任何支持Add的集合都可以用这种方式初始化。详情在C# Language Specification 4.0的7.6.10.3部分。

    应用集合初始值设定项的集合对象必须是实现 System.Collections.IEnumerable 的类型,否则会发生编译时错误。对于按顺序指定的每个指定元素,集合初始化程序调用目标对象的 Add 方法,并将元素初始化程序的表达式列表作为参数列表,对每个调用应用正常的重载决策。因此,集合对象必须包含适用于每个元素初始值设定项的 Add 方法。

    【讨论】:

    • 感谢语言规范中有关满足此要求所需的有用信息。这对我的理解很有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-15
    • 2011-08-18
    • 1970-01-01
    相关资源
    最近更新 更多