2009-03-26 16 views
19

この質問は、前の質問で提起されたものに対処していますが、私はそれを見つけることができませんでした。基底型のリストを継承型のリストに変換する

C#クラスには、基本クラスの汎用リストを引数とするメソッドがあります。私は継承されたクラスのリストを渡す必要があり、正確にこれを行う方法を知らない。私は試行錯誤しています。以下は、これを例示するサンプルコードです。

public class A 
{ 
    public static void MethodC(List<A>) 
    { 
     // Do Something here with the list 
    } 
} 
public Class B : A 
{ 
    // B inherits from A, A is the Base Class 
} 

// Code utilizing the above method 
List<B> listOfB = new List<B>(); 
A.MethodC((List<A>) listOfB); // Error: this does not work 
A.MethodC(listOfB.ToList<typeof(A)>()); // Error: this does not work 
A.MethodC(listOfB.ConvertAll<A>(typeof(A))); // Error: this does not work 
// how can I accomplish this? It should be possible I would think 

注:最終的な作業方法を参考にしています。私は自分の問題をさらに良く解決していますが、技術的には質問に答えが出ませんでした。

public static DataTable 
    ObjectCollectionToDataTable<GLIST> 
     (List<GLIST> ObjectCollection) where GLIST 
       : BaseBusinessObject 
     { 
      DataTable ret = null; 

      if (ObjectCollection != null) 
      { 
       foreach (var b in ObjectCollection) 
       { 

        DataTable dt = b.ToDataTable(); 
        if (ret == null) 
         ret = dt.Clone(); 
        if (dt.Rows.Count > 0) 
         ret.Rows.Add(dt.Rows[0].ItemArray); 
       } 
      } 

      return ret; 
     } 
+0

これは私があなたに与えた答えと同じです... –

+0

そして、それはあなたがもともと尋ねたものに対する技術的な答えです! :) –

答えて

29

あなたが利用できるLINQを持っている場合は、現在のC#バージョンにおける共分散の欠如に対処している

var ListOfA = ListOfB.Cast<A>().ToList(); 
+0

私はlinqを持っているとは思わないが、とにかく働いた。あなたの迅速な対応に心から感謝します。 – stephenbayer

+0

考えられる問題 - MethodCはMethodCの外でそれらの変更が見えるようにリストを変更する必要がありますか? –

+0

うれしかった!あなたがLINQ拡張メソッドを利用できると信じている唯一の理由は、あなたの例でToListを使用したことです。 –

9

これはできません。なぜ許可されていないのか理解するには、が、List<Base>にキャストされた後にList<Derived>で呼び出された場合にどうなるか想像してください。

また、C#4.0が異なることを意味する回答は間違っています。あなたがこれを行えるように、リストは決して変更されません。 IEnumerableのみが、コレクションにアイテムを追加できないためです。

更新:あなたが行った解決策では、同じリストを渡さなくなったためです。オリジナルのコピーであるまったく新しいリストを作成しています。これがリストの変更について尋ねられた理由です。 MethodCがリストの項目数を変更すると、元のリストではなくコピーが変更されます。

私は次のようにあなたのための理想的なソリューションだと思います。このソリューションで、あなたが最初にそれにその奇妙な変換を行うために必要とせずにMethodCに直接List<B>を渡すことができますどのように、

public abstract class A 
{ 
    public void MethodC<TItem>(List<TItem> list) where TItem : A 
    { 
     foreach (var item in list) 
      item.CanBeCalled(); 
    } 

    public abstract void CanBeCalled(); 
} 

public class B : A 
{ 
    public override void CanBeCalled() 
    { 
     Console.WriteLine("Calling into B"); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     List<B> listOfB = new List<B>(); 

     A a = new B(); 

     a.MethodC(listOfB); 
    } 
} 

お知らせ。不要なコピーは不要です。

Aのリストでなければならないと主張するのではなく、Aから派生したもののリストを受け入れるようにMethodCに言いました。

+0

私はそれが本当であるとは思わない、それはうまく動作します。私のメソッド呼び出しは、コレクションをループし、抽象メソッド(オーバーライド)とプロパティを処理します。上記のコードを以前のレスポンスで使用しましたが、うまく機能します。プロジェクトはコンパイラとしてCSC.exe(C#)3.0を使用した.NET 2.0です。 – stephenbayer

+0

上記の更新を参照してください。 –

+0

私はこの問題を解決するのが難しいと思っていますか? :) –

3

ここでは、誤ったタイプのリスト内のオブジェクトを除外する回答を示します。これは私の意見ではるかに安全な方法です:

List<A> ListOfA = ListOfB.OfType<A>().ToList(); 

OfTypeメソッドは、Castがエラーをスローする間違った派生クラスの項目を除外します。