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;

これが役立つ場所の良い例はControls、UI のコレクションです。あなたはこれを行うことができます:

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

初期化されていない変数 (Dictionary) を宣言したため、null 参照例外で失敗し、null になります。

初期化構文を使用してエントリを追加しようとすると、null オブジェクトにデータを書き込もうとしています。

この行を「= new Dictionary...」に置き換えると、Dictionary が参照する新しいオブジェクトが作成されるため、それにエントリを正常に追加できます。

(Jon Skeet の例では、Controls コレクションはフォームによって既に作成されている必要があるため、問題なく動作します)

于 2009-09-23T19:33:12.743 に答える