2013-06-06 9 views
24

の一覧を表示する一覧 から変換できません。私の List<DerivedClass>から List<BaseClass>までですが、コンパイラがこれを許可しない理由が分からない限り、私はそれをやっていて快適ではないと思います。 は、私は<code>BaseClass</code>のリストを取る関数に<code>DerivedClass</code>のリストを渡すためにしようとしているが、私はエラーを取得<BaseClass>

私が見つけた説明は、単に型の安全性に何らかの違反があると言っただけですが、私はそれを見ていません。誰か助けてくれますか?

List<DerivedClass>からList<BaseClass>への変換を許可するコンパイラの危険性はありますか? List<A>List<B>あり、その後、Bある – A場合は、記述している行動が共分散と呼ばれる

class Program 
{ 
    public static void Main() 
    { 
     BaseClass bc = new DerivedClass(); // works fine 
     List<BaseClass> bcl = new List<DerivedClass>(); // this line has an error 

     doSomething(new List<DerivedClass>()); // this line has an error 
    } 

    public void doSomething(List<BaseClass> bc) 
    { 
     // do something with bc 
    } 
} 

class BaseClass 
{ 
} 

class DerivedClass : BaseClass 
{ 
} 
+0

クラスはそのベースから派生しますが、 '一覧は' '一覧'から派生していません。 –

+0

@TimSchmelterこの種の継承は、 'Generic 'が 'Generic 'から派生したものとみなされる可能性があるということを意味しますか?あるいはそのような特徴が問題を引き起こすだろうか? –

+1

それはちょうどそのように実装されていません。 http://marcgravell.blogspot.fr/2009/02/what-c​​-40-covariance-doesn-do.html –

答えて

37

機能することは、IEnumerable<T>List<T>パラメータを変更すると、それが動作するはずです:

IEnumerable<BaseClass> bcl = new List<DerivedClass>(); 
public void doSomething(IEnumerable<BaseClass> bc) 
{ 
    // do something with bc 
} 

情報およそco-variant in generic

+0

.Net 4.5からは、メソッドがコレクション要素にランダムアクセスする必要がある場合に使用できる 'IReadOnlyList 'もあります。 – tia

11


は、ここに私のSSCCEです。

しかし、List<T>のような可変型の場合、それは基本的に危険です。

これが可能であれば、この方法では、実際にはDerivedClassを保持できるリストにnew OtherDerivedClass()を追加することができます。

不変型では共分散は安全ですが、.NETではインターフェイスと代理人でのみサポートされています。
あなたはList<T>は、ないco-variantin-variantあるので、あなたがco-variantサポートIEnumerable<T>に変更する必要がありますので、それはある

+0

@SamIam:いいえ。 'List 'を渡そうとしています。 'Derived'を含む' List 'を渡すとうまくいくでしょう。 – SLaks

+0

私の 'List 'を 'List 'にキャストまたは変換して渡す前に大丈夫でしょうか? –

+1

@ Samam:いいえ、全体のポイントは、 'List 'を 'List 'にキャストすることは基本的に安全ではないということです。 'List 'を作成すると、それが動作します。 – SLaks

1

に書くことができた場合

List<BaseClass> bcl = new List<DerivedClass>(); 

あなたはリストにDerivedClassないインスタンスを追加

var instance = new AnotherClassInheritingFromBaseClass(); 
bc1.Add(instance); 

を呼び出すことができます。

2

基本クラスから派生したクラスがある場合、それらのクラスのコンテナは自動的に派生しません。したがって、List<Derived>List<Base>にキャストすることはできません。そう、これは新しいリストであることを

List<MyDerived> list1 = new List<MyDerived>(); 
List<MyBase> list2 = list1.Cast<MyBase>().ToList(); 

ノートではなく、あなたの元のリストのキャスト版、この上の操作:各オブジェクトは、基本クラスにキャストバックされた新しいリストを作成する

使用.Cast<T>()新しいリストは元のリストに反映されません。ただし、含まれているオブジェクトに対する操作は反映されます。

+1

'List list2 = new List (list1);'私は「キャスト」を使用するよりもきれいに思います。 – Brian

38

Explanations that I have found have simply said that it violates type safety somehow, but I'm not seeing it. What is the risk of the compiler allowing conversion from List<DerivedClass> to List<BaseClass> ?

この質問はほとんど毎日尋ねられます。

List<Mammal>の動物のリストにのリストに入れることができるので、List<Animal>に変換することはできません。 A List<Mammal>はのリストにすでにの虎が存在する可能性があるため、List<Giraffe>に変換することはできません。

したがってList<T>はT.

不変なければならないトカゲを追加IEnumerable<Animal>に方法がないためしかし、List<Mammal>は(C#4.0のように)IEnumerable<Animal>に変換することができます。 IEnumerable<T>は私が使用した溶液は、拡張クラスを作成することでしたT.

+4

+1それをすべて説明する単純な動物学的説明。 (IEnumerable には、トカゲを追加するメソッドはありません - >私はちょうどその場合にチェックします;)) –

+0

私は気が気になりません...キリンは明らかですが、なぜあなたは哺乳動物を渡すことができません動物を扱うことができるものは、哺乳類以外の動物にも対応できるからです。 – MGOwen

+2

@MGOwen:あなたには哺乳動物のリストがあります。あなたはそれを動物のリストとして扱うことにします。あなたは動物のリストにトカゲを置く。 **しかしそれは本当に哺乳類のリストです**。今では、哺乳類のリストには哺乳類しかないという予想に反して、その中にトカゲを持つ哺乳類のリストがあります。結論は型システムに違反しているので、その手順の1つは違法でなければなりません。それは最初のものです:あなたは動物のリストとして哺乳動物のリストを扱うことはできません。 –

0

共変です:

public static class myExtensionClass 
{ 
    public void doSomething<T>(List<BaseClass> bc) where T: BaseClass 
    { 
     // do something with bc 
    } 
} 

それは一般的な使用していますが、あなたがそれを呼び出すときは、あなた以来クラスをespecifyする必要はありませんコンパイラが既に拡張クラスと同じ型であることを '通知'しています。

あなたはこのようにそれを呼び出します。

List<DerivedClass> lst = new List<DerivedClass>(); 
lst.doSomething(); 
関連する問題

 関連する問題