如何从基类列表中获取子类对象



让我们考虑一个示例层次结构

class BaseClass{}
class ChildClass1 : BaseClass{}
class ChildClass2 : BaseClass{}

现在我有一个BaseClass 类型的通用列表

List<BaseClass> sampleList = new List<BaseClass>();

在这个列表中,我添加了ChildClass1ChildClass2的对象。

现在,当访问这些对象时,我想对不同类型的对象执行不同的操作。使用if-else并检查对象是否为所需类型,我可以很容易地实现这一点。

class SampleClass
{
int Property{get;set;}
List<BaseClass> sampleList = new List<BaseClass>();
void DoCalculations()
{
foreach(var obj in sampleList)
{
if(obj is ChildClass1){//Do something to this.Property}
else if(obj is ChildClass2){//Do Somethingto this.Property}
}
}
}

然而,由于复杂性和性能问题,我希望避免使用if-elseswitch(我的真实案例包含大量派生类(。

因此,为了绕过这种情况,我想出了一种方法,让重载方法具有相同的名称但不同的类型(每个方法对应于每个派生类型(。

我想以某种方式迭代BaseClass并将其强制转换为ChlidClass对象,然后将其传递给DoSomething()方法,重载本身将负责执行哪个操作。然而,我无法从BaseClass中获得ChildClass类型的对象来动态工作。

我尝试过的是:

class SampleClass
{
int Property{get;set;}
List<BaseClass> sampleList = new List<BaseClass>();
public void DoCalculations()
{
foreach(var entry in sampleList)
{
Type type = entry.GetType();
var obj = entry as type; //getting error here
this.DoSomething(obj);
}
}
private void DoSomething(ChildClass1 obj){//Do something to this.Property}
private void DoSomething(ChildClass2 obj){//Do something to this.Property}
}

在上面的代码中,我只展示了一个属性int Property{get;set;}的使用,但在我的实际情况中,考虑了多个属性。有什么方法可以达到我的需要吗?

编辑:正如下面的评论和一些答案中所提到的,让DoSomething((在BaseClass((中成为一个方法并在ChildClass中覆盖它们,在我的情况下,这可能实际上不起作用,因为DoSometing((与它所定义的类的全局字段属性一起工作。它不是ChildClass对象特有的。

考虑将类设为BaseClassabstract,并给它一个abstract方法。ChildClass1ChildClass2两种类型都将被强制覆盖DoSomething()

如果由于某种原因无法使BaseClass抽象,您也可以在ChildClass1ChildClass2中使方法virtualoverride抽象

抽象方法:

abstract class BaseClass
{    
public abstract void DoSomething();
}
class ChildClass1 : BaseClass{
public override void DoSomething()
{
Console.WriteLine("Impl. 1");
}
}
class ChildClass2 : BaseClass{

private string _someRandomAttribute = "Impl. 2";
public override void DoSomething()
{
Console.WriteLine(_someRandomAttribute);
}
}

虚拟方法:

class BaseClass
{    
public virtual void DoSomething()
{
Console.WriteLine("Base implementation for types that don't override DoSomething()");
}
}
class ChildClass1 : BaseClass{
public override void DoSomething()
{
Console.WriteLine("Impl. for type ChildClass1");
}
}
class ChildClass2 : BaseClass{
public override void DoSomething()
{
Console.WriteLine("Impl. for type ChildClass2");
}
}

完成后,您将能够执行以下操作:

foreach(var obj in sampleList)
{
obj.DoSomething();
}

您应该使DoSomething成为BaseClass中的虚拟方法,并让派生类适当地覆盖它。然后,您可以简单地在任何实例上调用DoSomething

class BaseClass
{
virtual void DoSomething() { ... }
}
class Child1 : BaseClass
{
override void DoSomething() { Console.WriteLine("Child1"); }
}

现在您不需要检查类型,因为实例知道它的类型,因此运行时知道要调用哪个覆盖:

foreach(BaseClass obj in sampleList)
{
obj.DoSomething();
}

如果你想强制派生类实现DoSomething-方法,你甚至可以把它变成abstract。这是有意义的IMHO,除非你想实例化BaseClass

最新更新