List <T>をList <Interface>にキャスト


回答:


249

キャストすることはできません(参照IDを保持)-安全ではありません。例えば:

public interface IFruit {}

public class Apple : IFruit {}
public class Banana : IFruit {}

...

List<Apple> apples = new List<Apple>();
List<IFruit> fruit = apples; // Fortunately not allowed
fruit.Add(new Banana());

// Eek - it's a banana!
Apple apple = apples[0];

これで、共分散のために.NET 4 / C#4でa List<Apple>をに変換できますがIEnumerable<IFruit>List<IFruit>必要な場合は新しいリストを作成する必要があります。例えば:

// In .NET 4, using the covariance of IEnumerable<T>
List<IFruit> fruit = apples.ToList<IFruit>();

// In .NET 3.5
List<IFruit> fruit = apples.Cast<IFruit>().ToList();

しかし、これは元のリストをキャストすることと同じではありません。別個のリストです。これは安全ですが、一方のリストに加えられた変更はもう一方のリストに反映されないことを理解する必要があります。(もちろん、リストが参照するオブジェクトへの変更は表示されます。)


6
彼らが「まだ建物の中にいる」ように!
Andras Zoltan 2012年

1
共分散tolistを実行することと、新しいList <IFruit>()を実行することの違いは何ですか?次に、元のリストをforeachし、各アイテムをIFruitリストに追加しますか?foreachの方法では...オブジェクト参照は同じですよね?だから...それが本当なら、リスト全体を直接キャストすることはできないのは個人的にはほとんど意味がありません。?
Robert

3
@RobertNoack:「オブジェクト参照」とはどういう意味ですか?各要素のオブジェクト参照は同じですが、リスト参照自体をキャストすることと同じではありません。参照をキャストして、List<IFruit>実際にはへの参照であるコンパイル時の型の参照ができると仮定しますList<Apple>。これにBanana参照を追加するとどうなると思いますList<IFruit>か?
Jon Skeet、

1
ああ。読み方を学ぶ必要があると思います。元の答えは、リスト内のオブジェクトは深くコピーされて再作成されると言っていましたが、それは私には意味がありませんでした。しかし、同じオブジェクトで新しいリストのみが作成される部分は明らかに見逃しました。
Robert Noack 14

2
@TrươngQuốcKhánh:どのコードがどのように見えるのか、またはのusingディレクティブがあるのかSystem.Linq、それを呼び出そうとしているのか、私にはわかりません。さらに調査することをお勧めします。それでも解決しない場合は、最小限の再現可能な例で質問します。
Jon Skeet 2017

6

キャストイテレータと.ToList():

List<IDic> casted = input.Cast<IDic>().ToList() トリックを行います。

元々、共分散が機能すると述べましたが、ジョンが正しく指摘しているように; いいえ、そうではありません!

そして、もともと私は愚かにToList()電話をやめました


Cast安全ではないので、IEnumerable<T>ではなく、を返しますList<T>-そして、いいえ、共分散この変換を許可しません-私の答えを見てください。
Jon Skeet

リンクしたページから:「インターフェース型とデリゲート型のみがバリアント型パラメーターを持つことができます」
Jon Skeet

@ジョン-私はToList()あなたのコメントを読む前に欠落していることに気づきました; もちろん、もちろん示しましたが、共分散は機能しません。どー!
Andras Zoltan 2012年

正しい。共分散はCast、type引数をに指定する限り、.NET 4での呼び出しが不要であることを意味するため、引き続き役立ちますToList
Jon Skeet、2012年

5

私にもこの問題があり、Jon Skeetの回答を読んだ後、コードをList<T>からuse に変更しましたIEnumerable<T>。これはのOPの元の質問に答えるしませんが、私はキャストすることができますどのようにList<Client>するList<IDic>ため、それはそうする必要性を回避しないと、この問題が発生した他の人に役立つかもしれません。もちろん、これはの使用を必要とするコードがList<IDic>あなたの管理下にあると想定しています。

例えば:

public void ProcessIDic(IEnumerable<IDic> sequence)
{
   // Implementation
}

の代わりに:

public void ProcessIDic(List<IDic> list)
{
   // Implementation
}

3

LINQを使用できる場合、これを行うことができます...

List<Client> clientList = new List<Client>();
List<IDic> list = clientList.Select(c => (IDic)c).ToList();


0

新規に作成してList<IDic>すべての要素を転送することによってのみ可能です。


一般的な意味は他のすべての回答と同じであるため、なぜ反対票を投じたコメントがありますか?
Piotr Auguscik 2012年

新しいリストを作成することしかできないと言ったので、あなたは反対投票されたと思いますが、他の人は反対に投稿しました...私の反対投票ではありません)
musefan

まあ、彼らは新しいリストを作成しますが、実際に変更しない新しい演算子は使用しません。
Piotr Auguscik 2012年

0

.Net 3.5では、次のことができます。

List<ISomeInterface> interfaceList = new List<ISomeInterface>(list.Cast<ISomeInterface>());

この場合のListのコンストラクターはIEnumerableを取ります。ただし、
リストはIEnumerableにのみ変換可能です。myObjをISomeInterfaceに変換できる場合でも、IEnumerable型はIEnumerableに変換できません。


問題は、これがリストのコピーを作成することであり、ほとんどの場合、元のリストで操作を実行したい
2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.