我的同事告诉我,有可能将List<BaseClass>
转换为List<DerivedClass>
(他们没有向我展示一个有效的例子)。我没有想到可以将父类转换为子类(但我确实知道可以反过来这样做)。我已经看过几个相关的问题,人们说它无法完成,人们说它可以 - 所提议的解决方案都没有对我有用。我总是得到一个:
System.InvalidCastException.
Unable to cast object of type 'BaseClass' to 'ChildClass'
这绝对可能吗?如果是这样,我做错了什么?这是我的代码(为了这个问题而简化):
家长班:
public class ParentClass
{
public string Name = "";
}
儿童班:
public class ChildClass: ParentClass
{
public string Date = "";
}
转换:
List<ParentClass> parentList = ServiceApi.GetParentClassList().ToList();
List<ChildClass> childList = parentList.Cast<ChildClass>().ToList();
我的实际代码要复杂得多,但应遵循相同的原则。
答案 0 :(得分:10)
从某种意义上说,你是对的。
假设您有类型Animal
,Cat
(继承Animal)和Dog
(继承Animal)。 List<Animal>
可以同时包含Cats和Dogs,但List<Dog>
不能包含Cats。如果您的List<Animal>
包含Cat和Dog对象,那么您所做的任何事情都不会让您生成包含原始列表中所有内容的List<Dog>
。
所以从这个意义上来说,你是对的,你不能从List<DerivedClass>
产生List<ParentClass>
。
但有时候,作为程序员,您可以获得有关如何使用编译器无法使用的对象的信息。如果(且仅当)您可以知道特定List<Animal>
实例仅包含Dog
个对象,您可以随时说:
List<Dog> dogList = myAnimalListWithOnlyDogs.Cast<Dog>().ToList();
再次:这只有在您可以保证列表实例中的每个对象都可以转换为Dog对象时才有效。如果Cat对象以某种方式在列表中运行,那么在运行时最终会出现异常。然而,像这样的代码并不罕见。
从这个意义上说,同事是对的。当涉及到真正的工作代码时,人们无论如何都会做得很好,并且可以很好地使用它,尽管纯粹主义者可能认为这是代码气味,表明需要使用组合而不是继承。
此外,有时候List<Animal>
实例同时包含Cat和Dog对象,而您只关心Dog
个对象。在这种情况下,您可以这样做:
List<Dog> dogList = myAnimalList.OfType<Dog>().ToList();
这种模式在使用WinForms控件时尤其常见。
请注意,在这两种情况下,您都使用新序列。在序列中添加或删除对象不会更改原始对象。所以从这个意义上说,你已经不转换了原始的创建替代品。但是,序列包含相同的对象,因此在新序列中编辑Dog对象的属性将更改原始对象,因为它是相同的对象实例。
答案 1 :(得分:1)
Cast<T>
方法将强制转换操作应用于输入序列的所有元素。仅当您可以对序列的每个元素执行以下操作而不会导致异常时,它才有效:
ParentClass p = ...
ChildClass c = (ChildClass)p;
除非为p
分配了ChildClass
或其子类之一,否则这将无效。在您的情况下,从服务器API返回的数据似乎包含ParentClass
或ChildClass
以外的其中一个子类的对象。
您可以通过构建ChildClass
实例来解决此问题,假设您从服务器获得了足够的信息:
List<ChildClass> childList = parentList
.Select(parent => new ChildClass(parent.Name, ... /* the remaining fields */))
.ToList();
答案 2 :(得分:1)
未经测试,但这应该有效:
List<ParentClass> parentList = ServiceApi.GetParentClassList().ToList();
List<ChildClass> childList = parentList
.Where(x => x is ChildClass)
.Select(x => x as ChildClass)
.ToList();
您还可以使用评论中提到的OfType:
List<ChildClass> childList = parentList
.OfType<ChildClass>()
.ToList();
请参阅此.NET小提琴:https://dotnetfiddle.net/gDsNKi
答案 3 :(得分:1)
如果您愿意丢失演员表失败的项目,您可以使用OfType()
方法仅返回演员成功的项目。
var children = parentList.OfType<ChildClass>().ToList();