次のように、アイテムのリストをあるタイプから別のタイプにキャストすることは可能です(オブジェクトにキャストを実行するための静的で明示的な演算子メソッドがある場合)。
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
しかし、リスト全体を一度にキャストすることは不可能ですか?例えば、
ListOfY = (List<Y>)ListOfX;
次のように、アイテムのリストをあるタイプから別のタイプにキャストすることは可能です(オブジェクトにキャストを実行するための静的で明示的な演算子メソッドがある場合)。
List<Y> ListOfY = new List<Y>();
foreach(X x in ListOfX)
ListOfY.Add((Y)x);
しかし、リスト全体を一度にキャストすることは不可能ですか?例えば、
ListOfY = (List<Y>)ListOfX;
回答:
場合はX
、実際にキャストすることができY
ますが、使用することができるはずです
List<Y> listOfY = listOfX.Cast<Y>().ToList();
注意点(コメント投稿者へのH / T!)
using System.Linq;
この拡張メソッドを取得するには含める必要がありますList<Y>
はへの呼び出しによって作成されますToList()
。Cast<T>
メソッドはカスタム変換演算子をサポートしていないことにも注意してください。Linqキャストヘルパーが暗黙的キャストオペレーターで機能しないのはなぜですか。
直接キャストvar ListOfY = (List<Y>)ListOfX
は、型の共分散を必要とするためList<T>
不可能であり、すべてのケースで保証されるわけではありません。このキャストの問題の解決策については、以下をお読みください。
次のようなコードを書くことができるのは普通のようですが:
List<Animal> animals = (List<Animal>) mammalList;
すべての哺乳動物が動物になることを保証できるため、これは明らかに間違いです。
List<Mammal> mammals = (List<Mammal>) animalList;
すべての動物が哺乳類であるわけではないので。
ただし、C#3以降を使用すると、
IEnumerable<Animal> animals = mammalList.Cast<Animal>();
キャストが少し楽になります。これは、1つずつ追加するコードと構文的に同等です。明示的なキャストを使用Mammal
してリスト内のそれぞれをにキャストしAnimal
、キャストが成功しない場合は失敗します。
キャスト/変換プロセスをより詳細に制御したい場合は、提供された式を使用してアイテムを変換できるクラスのConvertAll
メソッドを使用できますList<T>
。のList
代わりにを返すという利点があるIEnumerable
ため、.ToList()
必要ありません。
List<object> o = new List<object>();
o.Add("one");
o.Add("two");
o.Add(3);
IEnumerable<string> s1 = o.Cast<string>(); //fails on the 3rd item
List<string> s2 = o.ConvertAll(x => x.ToString()); //succeeds
Swekoのポイントに追加するには:
キャストの理由
var listOfX = new List<X>();
ListOf<Y> ys = (List<Y>)listOfX; // Compile error: Cannot implicitly cast X to Y
ことができないためでList<T>
あるタイプTに不変ので、それはかどうかは関係ありませんX
から派生Y
)は-これがあるためであるList<T>
と定義されています。
public class List<T> : IList<T>, ICollection<T>, IEnumerable<T> ... // Other interfaces
(この宣言では、T
ここにタイプを追加する分散修飾子がないことに注意してください)
ただし、設計で可変コレクションが不要な場合は、たとえば次のようにGiraffe
派生する場合、不変コレクションの多くでアップキャストが可能Animal
です。
IEnumerable<Animal> animals = giraffes;
これはでIEnumerable<T>
共分散をサポートするためです。これは、コレクションから要素を追加または削除するメソッドをサポートしていないため、コレクションを変更できないことT
をIEnumerable
意味します。out
の宣言のキーワードに注意してくださいIEnumerable<T>
。
public interface IEnumerable<out T> : IEnumerable
(のような変更可能なコレクションがをサポートできないのに対し、不変のイテレータとコレクションはサポートできる理由の詳細な説明を次に示します。)List
covariance
キャスティング .Cast<T>()
他の人が述べたよう.Cast<T>()
に、コレクションに適用して、Tにキャストされた要素の新しいコレクションを投影できますがInvalidCastException
、1つ以上の要素へのキャストが不可能な場合は、これをスローします(これは、明示的に行うのと同じ動作です) OPのforeach
ループでキャスト)。
でのフィルタリングとキャスト OfType<T>()
入力リストに異なる互換性のないタイプの要素が含まれている場合は、の代わりにInvalidCastException
を使用することでこの可能性を回避できます。(変換を試みる前に、要素がターゲットタイプに変換できるかどうかを確認し、互換性のないタイプを除外します。).OfType<T>()
.Cast<T>()
.OfType<>()
foreach
OPがこれを代わりに作成した場合も注意してください:(で明示的Y y
に注意してくださいforeach
)
List<Y> ListOfY = new List<Y>();
foreach(Y y in ListOfX)
{
ListOfY.Add(y);
}
キャスティングも試みられること。ただし、キャストが不可能な場合は、InvalidCastException
結果になります。
例
たとえば、単純な(C#6)クラス階層があるとします。
public abstract class Animal
{
public string Name { get; }
protected Animal(string name) { Name = name; }
}
public class Elephant : Animal
{
public Elephant(string name) : base(name){}
}
public class Zebra : Animal
{
public Zebra(string name) : base(name) { }
}
混合タイプのコレクションを操作する場合:
var mixedAnimals = new Animal[]
{
new Zebra("Zed"),
new Elephant("Ellie")
};
foreach(Animal animal in mixedAnimals)
{
// Fails for Zed - `InvalidCastException - cannot cast from Zebra to Elephant`
castedAnimals.Add((Elephant)animal);
}
var castedAnimals = mixedAnimals.Cast<Elephant>()
// Also fails for Zed with `InvalidCastException
.ToList();
一方:
var castedAnimals = mixedAnimals.OfType<Elephant>()
.ToList();
// Ellie
象のみを除外します。つまり、シマウマは排除されます。
Re:暗黙のキャスト演算子
動的ではなく、ユーザー定義の変換演算子はコンパイル時にのみ使用されるため *たとえば、ZebraとElephantの間の変換演算子が使用可能になったとしても、変換に対するアプローチの上記の実行時の動作は変わりません。
ZebraをElephantに変換する変換演算子を追加すると、次のようになります。
public class Zebra : Animal
{
public Zebra(string name) : base(name) { }
public static implicit operator Elephant(Zebra z)
{
return new Elephant(z.Name);
}
}
その代わりに、上記変換演算子が与えられると、コンパイラは、アレイの下方からのタイプに変更することができるようになるAnimal[]
までのElephant[]
シマウマは今象の均一な集まりに変換することができることを考えると、。
var compilerInferredAnimals = new []
{
new Zebra("Zed"),
new Elephant("Ellie")
};
実行時の暗黙の変換演算子の使用
*エリックが述べたように、変換演算子は実行時に次の方法でアクセスできますdynamic
。
var mixedAnimals = new Animal[] // i.e. Polymorphic collection
{
new Zebra("Zed"),
new Elephant("Ellie")
};
foreach (dynamic animal in mixedAnimals)
{
castedAnimals.Add(animal);
}
// Returns Zed, Ellie
foreach
はフィルタリングしませんが、反復変数としてより派生型を使用すると、コンパイラーにキャストの試行を強制します。これは、準拠していない最初の要素で失敗します。
これはこの質問に対する答えではありませんが、一部の人にとっては役立つかもしれません。@ SWekoが言ったように、共分散と反変のおかげList<X>
でList<Y>
、にキャストすることはできませんが、にキャストするList<X>
ことができIEnumerable<Y>
、暗黙のキャストでも可能です。
例:
List<Y> ListOfY = new List<Y>();
List<X> ListOfX = (List<X>)ListOfY; // Compile error
だが
List<Y> ListOfY = new List<Y>();
IEnumerable<X> EnumerableOfX = ListOfY; // No issue
大きな利点は、メモリに新しいリストを作成しないことです。
dynamic data = List<x> val;
List<y> val2 = ((IEnumerable)data).Cast<y>().ToList();