2016-04-20 5 views
0

私はSystem.Collections.Specialized.StringDictionaryつまずいと、このようvarキーワードを使用して、そのエントリを反復処理しようとしています:StringDictionaryを反復処理は、C#で匿名型を使用して

StringDictionary sd = new StringDictionary(); 

sd.Add("key", "value"); 
foreach(var v in sd) 
{ 
    Console.WriteLine(v.Key); 
} 

私は、これはコンパイラエラーを生成することを発見して驚いた。

'object' does not contain a definition for 'Key' and no extension method 'Key' accepting a first argument of type 'object' could be found

varの代わりにSystem.Collections.DictionaryEntryを使用すると、すべて正常に機能します。何らかの理由で匿名型を使用していると、コンパイラはオブジェクトのコレクションとしてStringDictionaryを処理していますが、その理由を知りたいと思います。何が起こっているのですか?

ところで、私はforeachで実際に匿名タイプを使用するつもりはありません。私はそれがうまくいくと思ったように動作しない理由について疑問に思っています。ありがとうございました。

答えて

2

varはそれ自体匿名型ではありません。これは、型を推論するようにコンパイラに指示するキーワードです。 varを「推論型」と呼ぶことにします。型名を名前で参照することができないため、匿名型の状況でよく使用されます。しかし、それはここでの状況ではありません。

この場合、StringDictionaryは、非汎用のSystem.Collections.IEnumerableを実装しており、現在のアイテムのタイプにはobjectが使用されています。したがって、推定されるタイプvは、を持たないobjectです。この型にDictionaryEntryを挿入すると、コンパイラはキャストを挿入します。 vの他のタイプは実際にはコンパイルされますが、実行時には失敗します。

@hvdが指摘しているように、厄介なのは歴史の事故に過ぎません。 StringDictionaryは、ジェネリックコレクションタイプが導入されたため、誰も更新する必要がありませんでした。現在は、下位互換性のために維持されている履歴アーティファクトの一種です。 sourceの文書コメントを検討してください:

Consider this class obsolete - use Dictionary<String, String> instead with a proper StringComparer instance.

+0

Excelent答え、ありがとうございます。私は新しいコードで 'StringDictionary'を使用していません、私はちょうど古いコードでそれを見つけて、それと対話する必要がありました。 – Fila

+0

@FilipStočesそう、それは時々起こる。私は、 'var'を使うことが、このような場合を除いてほとんどの場合推奨されると思います。私は 'foreach'ループ変数に' var'を厳密に使用することで回避できる無効なキャストからのバグを見てきました。 –

3

System.Collections.Specialized.StringDictionaryは非常に古いクラスです。ジェネリックスがまだ存在しないとき、.NET Framework 1にはすでに存在していました。そのため、まず、作成時には、コンパイラに何も有用でない非汎用のIEnumerableインターフェイスしか実装できず、第2に、varキーワードが存在しないため、とにかくforeach (DictionaryEntry v in sd)と入力してください。 .NET 2.0が登場し、ジェネリックが利用可能になり、C#3が登場し、varキーワードが利用可能になったとき、クラスはジェネリックインターフェイスを実装するように更新されていたかもしれませんが、その時点ではほとんど問題はありませんでした。代わりに汎用Dictionary<TKey, TValue>を使用してください。

+0

ああ、私は参照してください。だから、ジェネリックコレクションを反復する間、コンパイラは、コレクション内のエントリのタイプを調べるときに、 'IEnumberable 'のT型を探しています。正しい? – Fila

+1

@FilipStočesはい、ただし直接はありません。これは 'GetEnumerator()'メソッドと結果の 'Current'プロパティを通過しています。 'IEnumerable'は' Object Current'というプロパティを持つ列挙子を返す 'GetEnumerator()'メソッドを提供します。 'IEnumerable 'は 'T Current'というプロパティを持つ列挙子を返す' GetEnumerator() 'メソッドを提供します。理論的には、クラスは*インタフェースから独立した 'GetEnumerator()'メソッドを提供できました。しかし、 'var'キーワードなしではそれほど役に立ちませんでした。 – hvd

+0

よろしくお願いします。 – Fila