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

我知道可以从一种types转换为另一种types的项目列表(假设你的对象有一个公共静态显式操作符方法来执行转换),如下所示:

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给评论者!)

直接转换var ListOfY = (List<Y>)ListOfX是不可能的,因为它需要与 List<T>types的共同/ var ListOfY = (List<Y>)ListOfX ,并且在任何情况下都不能得到保证。 请继续阅读,看看这个铸造问题的解决scheme。

虽然能够编写如下代码似乎是正常的:

 List<Animal> animals = (List<Animal>) mammalList; 

因为我们可以保证每个哺乳动物都是动物,这显然是一个错误:

 List<Mammal> mammals = (List<Mammal>) animalList; 

因为不是每个动物都是哺乳动物。

但是,使用C#3及以上版本,您可以使用

 IEnumerable<Animal> animals = mammalList.Cast<Animal>(); 

这简化了铸造一点点。 这在语法上等同于你的一个一个添加代码,因为它使用一个明确的Mammal来将列表中的每个Mammal都转换成一个Animal ,并且如果强制转换不成功则会失败。

如果您更喜欢投射/转换过程,则可以使用List<T>类的ConvertAll方法,该方法可以使用提供的expression式来转换项目。 它有额外的好处,它返回一个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 

你可以使用List.ConvertAll([从Y转换到T]);

要增加Sweko的观点:

投的原因

 var listOfX = new List<X>(); ListOf<Y> ys = (List<Y>)listOfX; // Compile error: Cannot implicitly cast X to Y 

是不可能的,因为genericsList<T>是不变的,因此X是否从Y导出并不重要)。

请看这里为什么像List这样的可变集合不能支持covariance

但是,如果不需要可变集合 ,则可以使用诸如

 IEnumerable<Animal> animals = giraffes; 

是可能的 ,如果Giraffe来源于Animal ,因为IEnumerable<T>支持T协方差 – 这是有道理的,因为IEnumerable推断集合不能被改变。

使用.Cast<T>投射

正如其他人所提到的, .Cast<T>可以应用于一个集合,以投射到T的新元素集合,但是如果在一个或多个元素上投射是不可能的,那么这样做会抛出一个InvalidCastException与在OP的foreach循环中进行显式types转换相同的行为)。

使用OfType<T>筛选和转换

如果input列表包含不同的,不兼容的types的元素,则可以通过使用.OfType<>而不是.Cast<>来避免潜在的InvalidCastException 。 ( .OfType<>检查元素是否可以转换为目标types。)

使用foreach()进行types过滤

还要注意的是,如果OP已经写了:(注意在foreach明确的Y y

 List<Y> ListOfY = new List<Y>(); foreach(Y y in ListOfX) { ListOfY.Add(y); } 

任何不是Y元素,或者不能被转换成Y元素将被跳过并从结果列表中消除。 即foreach(Y y in ListOfX){ ... Add(y) }等价于ListOfX.OfType<Y>

例子

例如,给定简单的(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) { } } 

使用混合types的集合时:

 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(); 

鉴于:

 foreach(Elephant animal in mixedAnimals) { castedAnimals.Add(animal); } // Ellie 

 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); } } 

相反,考虑到上述转换运算符,编译器将能够将下面的数组的types从Animal[]更改为Elephant[] ,因为斑马现在可以转换为同类的大象集合:

 var compilerInferredAnimals = new [] { new Zebra("Zed"), new Elephant("Ellie") }; 

*正如Eric所说,转换运算符可以通过dynamic访问:

 var mixedAnimals = new Animal[] // ie Polymorphic collection { new Zebra("Zed"), new Elephant("Ellie") }; foreach (dynamic animal in mixedAnimals) { castedAnimals.Add(animal); } // Returns Zed, Ellie