2009-09-23 8 views
10

次のコードはコンパイルが、NullReferenceExceptionで失敗します。C#辞書初期化子コンパイル矛盾

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> 

失敗する構文の目的はありますか?それ以外の場合には正常に使用できますか?あるいはこれはコンパイラの見落としですか?

答えて

32

ありませんが、それは、初期化構文:)のご理解の欠陥だ...間違いではありません

Dictionary = { ... } 

のアイデアは、呼び出し側が読み取りアクセス権を持っている場合のためである

コレクションのプロパティには、は、にアクセスできません。言い換えれば、このような状況:

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

基本的に、新しいコールを先に作成せずに、「追加」の呼び出しが終了します。だから、このコード:

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; 

これが有用であるところの良い例は、UIのControlsコレクションです。あなたはこれを行うことができます。

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

それは読み取り専用ですので、あなたが実際には、Controlsプロパティを設定できませんでした。

+0

をそれはコンストラクタによって作成された辞書に項目を追加するために使用されています。しかし、それは辞書に既にあるものを追加することです(コンストラクタが最初に項目を追加した可能性があります)ので、equals演算子の奇妙な使い方です。 –

+0

一種の、はい...しかし同時に、それはコレクションの初期値を設定するために使用されるので、そのように適合します。 –

+0

右。欠落している 'new'は赤旗だったはずですが、この構文を一度も使用していなかったので、私はequals演算子を文字通り使いすぎました。 –

0

変数(ディクショナリ)が初期化されていないため、ヌル参照例外が発生して失敗します。

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

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

(ジョンスキートの例では、Controlsコレクションが既にフォームで作成されている必要があり、したがって、それはOK作品)

+0

はい、もちろんです。私の質問は、なぜこの構文を許可するのですか? –

+0

十分に公正。Jonはあなたの質問に答えたので、あなたが失敗を理解していない場合に備えて、理由を記入すると思った。 –

4

あなたはまだあなたがコンストラクタにしたい構文を使用することができますので、

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