12

以下代码编译,但失败并显示NullReferenceException

class Test
{
    public Dictionary<string, string> Dictionary { get; set; }
}

static void Main(string[] args)
{
    var x = new Test
    {
        Dictionary =   // fails
        {
            { "key", "value" }, { "key2", "value2" }
        }
    };
}

如果您将标记为“失败”的行替换为以下内容,则它可以工作(如预期的那样):

Dictionary = new Dictionary<string, string> 

失败的语法有什么目的——它可以在其他情况下成功使用吗?或者这是编译器的疏忽?

4

3 回答 3

33

不,这不是一个错误……这是您对初始化语法的理解上的一个缺陷 :)

的想法

Dictionary = { ... }

适用于调用者对集合属性具有读取权限但没有写入权限的情况。换句话说,像这样的情况:

class Test
{
    private readonly Dictionary<string, string> dictionary 
        = new Dictionary<string, string>();
    public Dictionary<string, string> Dictionary { get { return dictionary; } }
}

基本上它最终是对 Add 的调用,但没有首先创建新集合。所以这段代码:

Test test = new Test { Dictionary = { { "a", "b"}, {"c", "d" } };

相当于:

Test tmp = new Test();
Dictionary<string, string> tmpDictionary = tmp.Dictionary;
tmpDictionary.Add("a", "b");
tmpDictionary.Add("c", "d");
Test test = tmp;

一个很好的例子就是ControlsUI 的集合。你可以这样做:

Form form = new Form
{
    Controls = 
    {
        new Button { Text = "Hi" }, 
        new TextBox { Text = "There" } 
    }
};

但您实际上无法设置Controls属性,因为它是只读的。

于 2009-09-23T19:23:54.643 回答
4

您仍然可以在构造函数中使用所需的语法:

Dictionary<string, string> dictionary = new Dictionary<string, string>
            {
                {"a", "b"},
                {"c", "d"}
            };
于 2011-07-21T14:05:51.520 回答
1

它因空引用异常而失败,因为您声明了一个未初始化的变量(字典),因此它为空。

当您尝试使用初始化程序语法将条目添加到其中时,您正在尝试将数据写入空对象。

当您用“= new Dictionary...”替换该行时,您正在创建一个供 Dictionary 引用的新对象,因此您可以成功地将条目添加到其中。

(在 Jon Skeet 的示例中,Controls 集合必须已经由 Form 创建,因此可以正常工作)

于 2009-09-23T19:33:12.743 回答