简体   繁体   中英

How to get a child class object from base class list?

Let's consider a sample hierarchy

class BaseClass{}

class ChildClass1 : BaseClass{}

class ChildClass2 : BaseClass{}

Now I have a generic list of type BaseClass

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

And in this list I am adding the objects of Both ChildClass1 and ChildClass2 .

Now when accessing these objects, I want to do different operations for different type of objects. I can easily achieve this using if-else and checking if object is of desired type.

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

However due to complexity and performance issues, I wanted to avoid the if-else or switch (My real case contains a huge number of derived classes).

So to get around the condition, I came up with an approach to have overloaded methods with same name but different types (each for every derived type).

I thought of somehow iterating and casting the BaseClass to ChlidClass objects and passing it to DoSomething() method and overloading will itself take care of which operation to execute. However, I am not able to get the object of ChildClass type from BaseClass to work dynamically.

What I have tried is :

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

In above code I have only shown the use of one property int Property{get;set;} , but in my real case consider more than one properties in play. Is there some way to achieve what I need?

Edit : As mentioned in below comments and few answers to have DoSomething() a method in BaseClass() and override them in ChildClasses, that might not actually work in my case as the DoSomething() works with global fields properties of the class it is defined in. It is not specific to the object of ChildClass.

Consider making your class BaseClass abstract and give it an abstract method. Both types ChildClass1 and ChildClass2 will be forced to override DoSomething()

In case you cannot make your BaseClass abstract for some reason you could also make the method virtual and then override it in ChildClass1 and ChildClass2

Abstract approach:

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

Virtual approach:

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

After you're done with that, you will be able to do the following:

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

You should make DoSomething a virtual method within BaseClass and let deriving classes override it appropriately. Then you can simply call DoSomething on whatever instance you have:

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

Now you don´t need to check for the type, as the instance knows its type and thus the runtime knows which override to call:

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

You can even make your DoSomething -method abstract , if you want to force deriving classes to implement it. This makes sense IMHO, unless you want to be able to instantiate BaseClass .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM