在 C# 中,是不是可以将 List<Child> 强制转换为 List<Parent>?
Posted
技术标签:
【中文标题】在 C# 中,是不是可以将 List<Child> 强制转换为 List<Parent>?【英文标题】:In C#, is it possible to cast a List<Child> to List<Parent>?在 C# 中,是否可以将 List<Child> 强制转换为 List<Parent>? 【发布时间】:2010-12-19 03:59:48 【问题描述】:我想做这样的事情:
List<Child> childList = new List<Child>();
...
List<Parent> parentList = childList;
但是,因为 parentList 是 Child 的祖先的 List,而不是直接的祖先,所以我无法做到这一点。是否有解决方法(除了单独添加每个元素)?
【问题讨论】:
这不是完全重复的,但这里有一个非常相似的问题:***.com/questions/1569774/ienumerablet-conversion 【参考方案1】:使用 LINQ:
List<Parent> parentList = childList.Cast<Parent>().ToList();
Documentation for Cast<>()
【讨论】:
请注意,这会创建childList
的副本,与@Andre Pena 的不使用LINQ 版本完全相同。
ListList<>
s 既不是协变的也不是逆变的。
@recursive true,因此您可以使用新的 Parent 对象列表进行迭代等。但是 List不允许直接强制转换,因为无法使其类型安全。如果你有一个长颈鹿列表,然后你把它放到一个动物列表中,你就可以把一只老虎放到一个长颈鹿列表中!编译器不会阻止您,因为当然老虎可能会进入动物列表。编译器可以阻止你的唯一地方是不安全的转换。
在 C# 4 中,我们将支持使用引用类型参数化的 SAFE 接口和委托类型的协变和逆变。详情请看这里:
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/
【讨论】:
更糟糕的是,如果编译器允许您这样做,您的列表最终会比预期的要小,因为老虎会吃掉一些长颈鹿。 如果“父”的类型参数是接口,有什么变化吗?看来协变集合接口解决了 OP 的原始问题。【参考方案3】:您可以通过使用应用扩展方法的 Linq 方法来做到这一点,即:
List<Parent> parentList = childList.Cast<Parent>().ToList();
【讨论】:
【参考方案4】:是的,你可以这样做
var result = List.And(x => x.Parent.All(b => b.ParentId == value));
【讨论】:
这似乎与 ORM 对象层次结构有关。有用的示例需要更多上下文。【参考方案5】:早在 2009 年,Eric 就曾戏弄我们说 C# 4 会发生变化。那么我们今天的立场是什么?
我的答案中使用的类可以在底部找到。为了更容易理解,我们将使用 Mammal
类作为“父”类,将 Cat
和 Dog
类用作“子类”。猫和狗都是哺乳动物,但猫不是狗,狗不是猫。
这仍然不合法,也不可能:
List<Cat> cats = new List<Cat>();
List<Mammal> mammals = cats;
为什么不呢?猫是哺乳动物,为什么我们不能将猫的列表分配给List<Mammal>
?
因为,如果允许我们在 List<Mammal>
变量中存储对 List<Cat>
的引用,我们就可以编译以下代码以将狗添加到猫列表中:
mammals.Add(new Dog());
我们不能允许这样!请记住,mammals
只是对cats
的引用。 Dog
不是 Cat
的后代,并且在 Cat
对象列表中没有任何业务。
Starting with .NET Framework 4,几个泛型接口具有使用 C# 4 中引入的out
泛型修饰符关键字声明的协变类型参数。这些接口中有IEnumerable<T>
,它当然是由List<T>
实现的。
这意味着我们现在可以将List<Cat>
转换为IEnumerable<Mammal>
:
IEnumerable<Mammal> mammalsEnumerable = cats;
我们无法向mammalsEnumerable
添加新的Dog
,因为IEnumerable<out T>
是“只读”接口,即它没有Add()
方法,但我们现在可以使用cats
可以使用 IEnumerable<Mammal>
的任何地方。例如,我们可以将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
【讨论】:
++为唯一找到问题症结的:只读接口 要点?这适用于 IEnumerable以上是关于在 C# 中,是不是可以将 List<Child> 强制转换为 List<Parent>?的主要内容,如果未能解决你的问题,请参考以下文章
C# 将Object类转化为List<T>类,其中T的类型不是object类型。
C#中list<>定义的变量,我用foreach()循环查找 与 list<> .find 查找两个哪个效率高?后者是不是用了算法
在 Typescript 中,有没有办法将一个类写成一个数组,所以我可以做 class[i],就像 C# 中的 List<T>