简体   繁体   中英

Passing a list of base class and obtain the concrete class

I have two concrete classes derived form a base class. Concrete classA has ten additional properties compared to concrete classB. I have a method where one of the parameters is the list of base class, like so: List<baseClass> . Inside the method I have to loop through the list, and cast to the appropriate concrete class and access the properties. Please let me know how to achieve this. Is there any good design pattern to do this?

c# has a GetType method that you can look into.

you also have the is operator

if (baseClass is derivedClass)
{
    // do what you will with derived class.
}

But

generally what your doing is a bad design pattern in the first place. when you iterate through your base class and then cast to a derived class, the whole point of polymorphism is lost.

Maybe you can make a method in your base class that can do the kinds of operations you need to do.

This is the basic approach:

foreach(baseClass x in theList)
{
   if (x is classA)
   {
       classA a = (classA) x;
       ...
   }
   else if (x is classB)
   {
       classB b = (classA) x;
       ...    
   }
}

It doesn't get much simpler when you need to split out multiple types. You can try to avoid the whole thing with interfaces or a different inheritance model. Impossible to say exactly without seeing more details.

I guess C#'s dynamic type can be your friend here.

class BaseClass {}

class ConcreteClass1 : BaseClass
{
    void Display1 () {}
}

class ConcreteClass2 : BaseClass
{
    void Display2 () {}
}

void Enumerate (List<BaseClass> baseItems)
{
    foreach (BaseClass baseItem in baseItems)
    {
        ConcreteAccessor ((dynamic)baseItem);
    }
}

void ConcreteAccessor (ConcreteClass1 concreteItem1)
{
    concreteItem1.Display1 ();
}

void ConcreteAccessor (ConcreteClass2 concreteItem2)
{
    concreteItem2.Display2 ();
}    

The key here is that you have different overloads one per each concrete class and call one of them in a seamless way using dynamic . The beauty is that the overload is resolved at run-time making your code looking clean.

Because it is a run-time type resolving, compile-time validation is not performed. Assume you miss an overload for one of your concrete types and the run-time resolves baseItem to that particular concrete type. Then it results in run-time error - crash - because there is no overload.

One more catch is that dynamic uses Reflection under the hood. As you know, Reflection slows your application.

foreach(var baseClass in baseClasses)
{
    if(baseClass.GetType() == typeof(ClassA)
    {
       var myClassA = (ClassA) baseClass;
        dowork();
    }
    else if(baseClass.GetType() == typeof(ClassB)
    {
       var myClassB = (ClassB) baseClass;
        dowork();
    }

}

To avoid explicit cast I suggest you to proceed in a different way: In your base class put an abstract method that will work with properties of your concrete classes.

For example:

public abstract void DoSomethingUsingProperties();

In your concrete classes implement (override) it with the right business logic.

Then, in your method where one of the parameters is the list of base class you can do something like this:

public void YourMethod(List<BaseClass> list, ...other params)
{
    // ...

    foreach(var bc in list)
    {
        // so you don't need to know specific properties of concrete classes...
        bc.DoSomethingUsingProperties();
    }

    //...
}

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