简体   繁体   English

C#字典初始化程序编译不一致

[英]C# dictionary initializer compilation inconsistency

The following code compiles, but fails with a NullReferenceException : 以下代码编译,但失败并出现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" }
        }
    };
}

If you replace the line marked 'fails' with the following, it works (as expected): 如果用以下内容替换标记为“失败”的行,则可以正常工作(如预期的那样):

Dictionary = new Dictionary<string, string> 

Is there any purpose to the failing syntax--can it be used successfully in some other case? 失败的语法是否有任何目的 - 是否可以在其他情况下成功使用? Or is this an oversight in the compiler? 或者这是编译器的疏忽?

No, it's not a mistake... it's a flaw in your understanding of initialization syntax :) 不,这不是一个错误......这是你理解初始化语法的一个缺陷:)

The idea of the 的想法

Dictionary = { ... }

is for cases where the caller has read access to a collection property, but not write access. 适用于调用者具有对集合属性的访问权但不具有访问权的情况。 In other words, situations like this: 换句话说,这样的情况:

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

Basically it ends up being calls to Add, but without creating a new collection first. 基本上它最终会调用Add,但不会先创建新的集合。 So this code: 所以这段代码:

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

is equivalent to: 相当于:

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

A good example of where this is useful is with the Controls collection for a UI. 这有用的一个很好的例子是UI的Controls集合。 You can do this: 你可以这样做:

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

but you couldn't actually set the Controls property, because it's read-only. 但你实际上无法设置 Controls属性,因为它是只读的。

You can still use the syntax you want in a constructor: 您仍然可以在构造函数中使用所需的语法:

Dictionary<string, string> dictionary = new Dictionary<string, string>
            {
                {"a", "b"},
                {"c", "d"}
            };

It fails with a null reference exception because you have declared a variable (Dictionary) that is unintialised, hence it is null. 它因空引用异常而失败,因为您声明了一个未初始化的变量(Dictionary),因此它为null。

When you attempt to add the entries into it using the initialiser syntax, you are trying to write data into a null object. 当您尝试使用初始化语法将条目添加到其中时,您尝试将数据写入空对象。

When you replace the line with a "= new Dictionary...", you are creating a new object for Dictionary to reference, and hence you are then able to add entries into it successfully. 当您使用“= new Dictionary ...”替换该行时,您正在为要引用的Dictionary创建一个新对象,因此您可以成功地向其中添加条目。

(In Jon Skeet's example, the Controls collection must already have been created by the Form, hence it works ok) (在Jon Skeet的例子中,Controls集合必须已经由Form创建,因此它可以正常工作)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM