为了账号安全,请及时绑定邮箱和手机立即绑定

从List <X>转换为List <Y>的语法较短?

从List <X>转换为List <Y>的语法较短?

C#
茅侃侃 2019-09-20 15:08:03
我知道有可能将一个项目列表从一种类型转换为另一种类型(假设您的对象有一个公共静态显式运算符方法来执行转换),一次一个:List<Y> ListOfY = new List<Y>();foreach(X x in ListOfX)    ListOfY.Add((Y)x);但是不可能一次投出整个列表吗?例如,ListOfY = (List<Y>)ListOfX;
查看完整描述

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


查看完整回答
反对 回复 2019-09-20
  • 3 回答
  • 0 关注
  • 609 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信