3 回答
TA贡献1943条经验 获得超7个赞
添加到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如果不能在一个或多个元素上强制转换(这与执行显式的行为相同)在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[],因为Zebras现在可以转换为同类的Elephants集合:
var compilerInferredAnimals = new []
{
new Zebra("Zed"),
new Elephant("Ellie")
};
在运行时使用隐式转换运算符
*正如Eric所述,转换运算符可以在运行时通过诉诸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
- 3 回答
- 0 关注
- 609 浏览
添加回答
举报