C# Linq `List<Interface>.AddRange` メソッドが機能しない
質問
以下のように定義されたインターフェースがあります。
public interface TestInterface{
int id { get; set; }
}
そして、そのインターフェイスを実装する 2 つの Linq-to SQL クラス:
public class tblTestA : TestInterface{
public int id { get; set; }
}
public class tblTestB : TestInterface{
public int id { get; set; }
}
tblTestA と tblTestB からのデータベース レコードによって設定された IEnumerable リスト a と b があります。
IEnumerable<tblTestA> a = db.tblTestAs.AsEnumerable();
IEnumerable<tblTestB> b = db.tblTestBs.AsEnumerable();
ただし、以下の場合は許可されません。
List<TestInterface> list = new List<TestInterface>();
list.AddRange(a);
list.AddRange(b);
次のようにしなければなりません:
foreach(tblTestA item in a)
list.Add(item)
foreach(tblTestB item in b)
list.Add(item)
何か間違っていることがあるでしょうか?助けてくれてありがとう
解決
Generic Covariance のため、C#4で機能します。以前のバージョンのC#とは異なり、IEnumerable<tblTestA>
からIEnumerable<TestInterface>
への変換があります。
機能はV2からCLRにありましたが、C#4でのみ公開されています(そしてフレームワークの種類は.NET 4の前にそれを利用しませんでした)。 のみは、一般的なインターフェイスに適用され、参照タイプのみ(例えば、IEnumerable<int>
からIEnumerable<object>
への変換はありません。)それはそれが理密になるところにのみ機能します - IEnumerable<T>
は共変動です。オブジェクトはAPIの「OUT」になるだけで、IList<T>
はそのAPIでも値を追加することができます。
一般的なコントラクシアンスもサポートされていて、他の方向に機能します。たとえば、IComparer<object>
からIComparer<string>
に変換できます。
C#4を使用していない場合は、Enumerable.Cast<T>
を使用するというTIMの提案は良いものです - あなたは少し効率を失いますが、それは機能します。
汎用分散についてもっと知りたい場合は、Eric Lippertに NDCビデオページ
他のヒント
あなたは何も悪いことをしていない:List<TestInterface>.AddRange
はIEnumerable<TestInterface>
を期待しています。IEnumerable<tblTestA>
またはIEnumerable<tblTestB>
を受け入れません。
あなたのforeach
ループは作業します。あるいは、Cast
を使用して型を変更できます。
List<TestInterface> list = new List<TestInterface>();
list.AddRange(a.Cast<TestInterface>());
list.AddRange(b.Cast<TestInterface>());
. AddRangeはインタフェースオブジェクトのリストを期待しており、あなたの "A"と "B"さまだは派生クラスオブジェクトのリストであると定義されています。明らかに、.NETは、それが実際にインタフェースを実装するために、そのジャンプを作成し、それらをインタフェースオブジェクトのリストとして扱うことが合理的であるようです。
しかし、この能力(「共分散」と呼ばれる)が.NET 4.0に追加されましたが、それにアップグレードするまでは、ループで立ち往生しているか、またはToArray()を呼び出してから結果をキャストしてみてください。TaskInterface []、または各項目の場合のLINQクエリと新しいリストなどを作成してください。
a
そして b
タイプのものです IEnumerable<tblTestA>
そして IEnumerable<tblTestB>
その間 list.AddRange
パラメータは次の型である必要があります IEnumerable<TestInterface>