2009-04-19 8 views
3

文字列をオブジェクトにアップキャストできますが、オブジェクトのIListに文字列のIListをアップスケールできません。どうして?新しいIListにすべてのアイテムをコピーすること以外は何をすべきか?C#:Generics内でのキャストはありませんか?

static void ThisWorks() 
{ 
    IList<object> list = new List<object>(); 
    list.Add("I can add a string since string : object"); 
} 

static void ThisDoesNotWork() 
{ 
    // throws an invalid cast exception 
    IList<object> list = (IList<object>) new List<string>(); 

    list.Add("I'm never getting here ... why?"); 
} 

答えて

4

ルック:バナナは果実がある一方で、バナナのバスケットは、あなたがにオレンジを追加することができるので、フルーツのバスケットではありません前者ではなく後者である。 List<string>にはList<object>よりも強い制約があります。

キャスティングは常にLiskowを尊重する必要があります。変更を許可しないコンテナやイテレータの場合、このようなキャストは安全ですが、変更が可能になると、薄い氷の近くでスケートしています。

+0

これはLSPを尊重しています。彼は、より派生した型(文字列)を* less *派生型(オブジェクト)として扱います。一般的に、これは安全であると考えられています。 –

+0

いいえ。彼はバナナバスケットからフルーツバスケットを作ろうとしている。彼が読んでいる限り、それは安全ですが、文字列が追加されていないと状況が変わってしまいます。 –

+1

実際には、** safe ** generic co/contravarianceをサポートするC#4.0のように、これが可能である可能性があるため、あなたの例は完全に真実ではありません。 –

7

ジェネリックが不変(C#3.0以降)であるため、これはできません。彼らは関係のないタイプですIList<object>から継承していないが、objectIList<string>から

var objectList = list.Cast<object>().ToList(); 
+0

ジェネリック*が不変であると言っていると思います。彼らは*共変*ではありません。彼らはC#4になります。 –

+0

ええ、私は気づいて、私はすでにそれを修正しました:) –

+0

@ジョン:C#4でも、特定のものだけが共変になります。特に、クラスはバリアントにすることはできません。デリゲートとインターフェイスのみです。 –

1

string継承し、そのためのあなたは、それらの間にキャストすることはできません。

あなたはでそれを回避することができます。

ただ、これは働いていた場合にどうなるかと思います。このようなことで

// THIS CODE DOES NOT WORK 
IList<object> list = new List<string>(); // this doesn't compile 
list.Add(5); // because this is perfectly valid on IList<object> but not on IList<string> 
4

あなたの質問は本質的にはのContravariance and Covarianceです。これは、同じ継承階層内の2つのクラスのオブジェクトに関して、メソッドとコレクションがどのようにふるまうかについて説明するプログラミング言語の概念です。 Wikipedia articleを読むと、上記の好奇心を、より大きくより一般的な視点に置くのに役立ちます。

関連する問題