7

私は以下のように定義されたインターフェースを持っています:

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)

私が間違っていることはありますか?助けてくれてありがとう

4

4 に答える 4

9

これは、ジェネリック共分散のため、C#4で機能します。以前のバージョンのC#とは異なり、からIEnumerable<tblTestA>への変換がありIEnumerable<TestInterface>ます。

この機能はv2からCLRに含まれていますが、C#4でのみ公開されています(フレームワークタイプは.NET 4より前でもこの機能を利用していませんでした)。これは、ジェネリックインターフェイスとデリゲート(クラスではなく)にのみ適用され、参照型にのみ適用されます(たとえば、からIEnumerable<int>への変換はありません)。また、意味のある場合にのみ機能します。オブジェクトはAPIから「出てくる」だけなので、共変です。一方、そのAPIでも値を追加できるため、は不変です。IEnumerable<object>IEnumerable<T>IList<T>

一般的な共変性もサポートされており、他の方向に機能します。たとえば、からIComparer<object>に変換できますIComparer<string>

C#4を使用していない場合は、Timによる使用の提案はEnumerable.Cast<T>適切です。効率は少し低下しますが、機能します。

一般的な分散について詳しく知りたい場合は、Eric Lippertがそれについての長い一連のブログ投稿を持っています。私は、 NDCビデオページで見ることができるNDC2010でそれについて話しました。

于 2010-07-14T09:49:45.780 に答える
6

あなたは何も悪いことをしていません: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>());
于 2010-07-14T09:47:28.607 に答える
1

AddRangeは、インターフェイスオブジェクトのリストを想定しており、「a」および「b」変数は、派生クラスオブジェクトのリストとして定義されています。明らかに、.NETが論理的にジャンプして、インターフェイスオブジェクトのリストとして扱うことができるのは合理的であるように思われます。これは、実際にインターフェイスを実装しているためです。そのロジックは、3.5までは.NETに組み込まれていませんでした。

ただし、この機能(「共分散」と呼ばれる)は.NET 4.0に追加されていますが、それにアップグレードするまでは、ループに陥るか、ToArray()を呼び出して結果をTaskInterface[]にキャストしてみてください。 、または各アイテムをケースに入れて新しいリストを作成するためのLINQクエリなど。

于 2010-07-14T09:56:19.797 に答える
0

aおよびbはタイプIEnumerable<tblTestA>であり、IEnumerable<tblTestB>
Whilelist.AddRangeはパラメータがタイプである必要がありますIEnumerable<TestInterface>

于 2010-07-14T09:48:34.783 に答える