2016-07-18 25 views
19

は、次のコードスニペットを参照してください:IDictionary <TKey、TValue>をIEnumerable <object>にアップキャスティングするのが失敗するのはなぜですか?

(IEnumerable<object>)new Dictionary<string, string>() 

上記キャストが無効なキャスト例外がスローされます。

実際には、IDictionary<TKey, TValue>ICollection<T>を実装しているため、間接的にIEnumerable<out T>を実装しています。つまり、キャスト全体が有効である必要があります。実際に

は、私にとってそれは私がデバッガ時計スロット上の全キャスト、を実行した場合、それはを動作することをさらに奇妙です!

Enter image description here

何が起こっているの?

+1

@PatrickHofmanそうでないのはなぜ?共変タイプのパラメータを持つ 'IEnumerable 'というインターフェースが1つしかありません。共分散が値の型ではうまくいかなくても... ...間違っていますか? –

+0

@CodeCasterインターフェイス自体が 'IEnumerable ' –

+0

@CodeCasterArgh、https://msdn.microsoft.com/en-us/library/9eekhta0(v=vs.110)という意味です。aspx –

答えて

24

この辞書はIEnumerable<KeyValuePair<TKey, TValue>>IEnumerableを実装していますが、構造体のIEnumerableはオブジェクトのIEnumerableと同じではありません。 Variance only works for reference-types

これが私の最後の仕事をして、論理的な選択のようになります。サンプルとして

var x = (IEnumerable)new Dictionary<string, string>(); 

、この作業を行います。

List<string> l = new List<string>(); 
var x = (IEnumerable<object>)l; 

しかし、これはしていません:

List<DateTime> l2 = new List<DateTime>(); 
var x = (IEnumerable<object>)l2; 

構造体が問題であることを明確に示します。

(それはあなたのウォッチウィンドウで働くなぜ、私は知らない)

+0

しかし、 'IEnumerable 'は共変です! –

+0

これは、同じキャストの時計がすでに動作する理由を説明していません! –

+0

'KeyValuePair 'はクラスではなく構造体なので、 –

4

私はKeyValuePairが値型であるため、これがあると思います。

この失敗します:

List<int> ints = new List<int>(); 
var objs = (IEnumerable<object>)ints; 

これは動作します:

List<string> ints = new List<string>(); 
var objs = (IEnumerable<object>)ints; 

同じ辞書のために行きます。

+0

あなたは絶対に正しいです。今のところ、パトリックの答えを受け入れるべきですが、Eric Lippertのような人が、なぜデバッガが私たちよりも力があるのか​​、私たちに答えることは素晴らしいことでしょう! –

+0

これは、デバッグツールの解析バグに過ぎないと思います。私は彼らが実際にその声明を実際にコンパイルし、それを評価するとは思わない。 @MatíasFidemraizer –

+1

@PatrickHofmanええ、そうすべきです...それはバグと見なすことができます。デバッガは実際のランタイム動作と100%コヒーレントではありません。\ –

0

これは奇妙です。あなたのコードスニペットは.NET 4.0でうまく動作します。 IEnumerableにキャストすることをおすすめします。

読む:IDictionary Interface(MSDN)

+1

これはもっと爆笑ですね。 –

+1

それは本当ですか?私はすでに自分で試してみましたが、同じ例外がスローされます –

+0

確かに、それは.net4.0で動作し、.net4.5で失敗します。とにかく、Patrick Hofmanとuser3185569がそれを釘付けにした。 KeyValuePairは構造体であるため、MSDNからIEnumerable >、IEnumerable を実装していません。私はパトリック・ホフマンの答えを受け入れることをお勧めします –

1

あなたが本当に平野IEnumerableと一緒に暮らすことができない場合は、これを試してみてください。

new Dictionary<string, string>().Cast<object>(); 
+0

それは問題ではありません。 OPはそれを確かに知っている。彼はちょうどなぜこれが起こるか知りたいと思う。 –

+0

ええ、絶対に。問題は、 'Enumerable.Cast'を呼び出すと**新しい列挙型**が生成され、同じインスタンスを保持し、それを型全体で実装された別のインタフェースにキャストする必要があります。 –

+0

' Dictionary 'をサブクラス化できますか?可能であれば、 'IEnumerable 'を実装することができます。 –

関連する問題