web-dev-qa-db-ja.com

C#では、List <Child>をList <Parent>にキャストできますか?

私はこのようなことをしたい:

List<Child> childList = new List<Child>();
...
List<Parent> parentList = childList;

ただし、parentListは リスト 直接の祖先ではなく、子供の祖先の、私はこれを行うことができません。回避策はありますか(各要素を個別に追加する以外)?

50
Matthew

タイプセーフにする方法がないため、直接キャストすることはできません。キリンのリストがあり、それを動物のリストにキャストした場合、キリンのリストにトラを入れることができます!もちろん、虎は動物のリストに入るかもしれないので、コンパイラはあなたを止めません。コンパイラがあなたを止めることができる唯一の場所は、安全でない変換です。

C#4では、SAFEインターフェイスと参照型でパラメーター化されたデリゲート型の共分散と反分散をサポートします。詳細はこちらをご覧ください:

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

60
Eric Lippert

LINQの使用:

_List<Parent> parentList = childList.Cast<Parent>().ToList();
_

Cast<>()のドキュメント

71
recursive

2009年に、エリックはC#4で状況が変わることを教えてくれました。

私の回答で使用したクラスは下部にあります。これを理解しやすくするために、「親」としてMammalクラスを使用し、「子」としてCatおよびDogクラスを使用します。猫と犬は両方とも哺乳類ですが、猫は犬ではなく、犬は猫ではありません。

これはまだ合法ではなく、次のことはできません。

_List<Cat> cats = new List<Cat>();

List<Mammal> mammals = cats;
_

何故なの?猫は哺乳類なので、猫のリストを_List<Mammal>_に割り当てられないのはなぜですか?

なぜなら、_List<Cat>_への参照を_List<Mammal>_変数に格納できる場合、次のコードをコンパイルして、犬を猫のリストに追加できるからです。

_mammals.Add(new Dog());
_

それを許してはいけません! mammalscatsへの単なる参照であることに注意してください。 DogCatから派生せず、Catオブジェクトのリストに含まれるビジネスはありません。

。NET Framework 4以降 、いくつかのジェネリックインターフェイスには、C#4で導入された out Generic Modifierキーワードで宣言された共変型パラメーターがあります。 _IEnumerable<T>_ これはもちろん_List<T>_によって実装されます。

これは、canが_List<Cat>_を_IEnumerable<Mammal>_にキャストすることを意味します。

_IEnumerable<Mammal> mammalsEnumerable = cats;
_

_IEnumerable<out T>_は「読み取り専用」インターフェースであるため、新しいDogmammalsEnumerableに追加できません。つまり、Add()メソッドはありませんが、 canは、_IEnumerable<Mammal>_を消費できる場所であればどこでもcatsを使用します。たとえば、mammalsEnumerableを_List<Dog>_と連結して、新しいシーケンスを返すことができます。

_void Main()
{
    List<Cat> cats = new List<Cat> { new Cat() };
    IEnumerable<Mammal> mammalsEnumerable =
        AddDogs(cats); // AddDogs() takes an IEnumerable<Mammal>
    Console.WriteLine(mammalsEnumerable.Count()); // Output: 3. One cat, two dogs.
}

public IEnumerable<Mammal> AddDogs(IEnumerable<Mammal> parentSequence)
{
    List<Dog> dogs = new List<Dog> { new Dog(), new Dog() };
    return parentSequence.Concat(dogs);
}
_

クラス定義:

_public abstract class Mammal { }

public class Cat: Mammal { }

public class Dog : Mammal { }
_
5
Stephen Kennedy

はい、次のようにできます

var result = List.And(x => x.Parent.All(b => b.ParentId == value));
0
caras