views:

224

answers:

7

I have base class BaseClass and derived classes DerivedA, DerivedB, and DerivedC that all inherit BaseClass.

I have another class, ExternalClass with a method that accepts a parameter of type BaseClass, but is actually passed a derived class. What is the best way to differentiate between these classes in ExternalClass if I wanted to perform a different action based on which derived class it received?

I was thinking of doing a Select but I'm not exactly sure how.

Thanks

+15  A: 

Your design is very likely to be flawed. You should consider making the behavior a method of BaseClass and override it in each derived class. You shouldn't check for the actual type of the object.

That is, ExternalClass should just call a method declared in BaseClass regardless of the actual type. Since the method is overriden by derived classes, the appropriate implementation will be called.

That said, to check if an object is an instance of a type or its derived classes, you can use the is operator:

if (obj is DerivedA) // C#
If TypeOf obj Is DerivedA Then ' // VB

If you want to check if the object is an instance of a specific type (and not its derived types):

if (obj.GetType() == typeof(DerivedA)) // C#
If obj.GetType() Is GetType(DerivedA) Then ' // VB
Mehrdad Afshari
hm. i see.
Jason
+1 solid advice. If you ever find yourself doing a switch on a class type in an inheritance tree, you're probably doing something wrong.
womp
thanks for letting me know i'm going about it wrong. this is helpful for sure.
Jason
@womp - what if i am in a UserControl that has the `BaseClass` as a member and must instantiate it via only the ID passed to it as a parameter. How do I know which derived class to instantiate unless I also pass along something like an enumerated value to tell it which one?
Jason
Jason: Use a factory method which uses a prepopulated `Dictionary<IdType, Func<BaseClass>>` to lookup the instantiation function of each derived class and call it. That's really a separate thing. You are not switching on "type" of an object. You're switching on the ID passed and "creating" the class. In the currect question, you have an object that's supposed to behave differently based on the type, which is what polymorphism does.
Mehrdad Afshari
You can do it without getting the type of the class, but with visitor as I wrote it below.
Yaroslav Yakovlev
Did you read the answer? I was basically saying the same thing.
Mehrdad Afshari
Mehrdad, no, you wrote that he should implement method in a base class, that would be overriden in children. So the operation executed by External class is delegated to children. I`m talking about implementing this operation by ExternalClass itself, just with the use of Visitor pattern. So I read what you wrote and wrote a bit different thing.
Yaroslav Yakovlev
+2  A: 

This is precisely what polymorphism is designed to let you do, frequently riding under the tagline "select is harmful." A good rule of thumb: you should never have to use a select statement to differentiate between different types of objects.

Create a method on BaseClass, even if it's abstract and does nothing. This communicates (to humans and to compilers) that all subclasses of BaseClass need to implement that operation. Then implement it appropriately in DerivedA, DerivedB, and DerivedC.

This way, simply having a variable declared as type BaseClass entitles you to call that method. It's up to ASP.NET to work out which specific implementation is appropriate based on the type of object you actually end up having.

VoteyDisciple
A: 

While I totally agree with Mehrdad, here's how you can check for the type of an object:

public MyMethod(BaseClass obj)
{
  if (obj is DerivedA) { ... }
  if (obj is DerivedB) { ... }
}
M4N
To be picky, this tests whether an object can be cast to DerivedA, not whether it is DerivedA. If DerivedA had a child named DerivedAPrime, it would pass the first test, which may or may not be a good thing.
Steven Sudit
+1  A: 

Here's a very simple example:

using System;

public abstract class BaseClass
{
    public abstract void SomeAction();
}

public class DerivedA : BaseClass
{
    public override void SomeAction()
    {
        Console.WriteLine("A!");
    }
}

public class DerivedB : BaseClass
{
    public override void SomeAction()
    {
        Console.WriteLine("B!");
    }
}

public class ExternalClass
{
    public static void Main()
    {
        DoIt(new DerivedA());
        DoIt(new DerivedB());

        Console.ReadLine();
    }

    public static void DoIt(BaseClass baseClass)
    {
        baseClass.SomeAction();
    }
}

Presumably your real-world ExternalClass would be non-static, of course.

Alternately you can use the following to share behavior:

public class BaseClass
{
    public virtual void SomeAction()
    {
        Console.WriteLine("Base!");
    }
}

public class DerivedA : BaseClass
{
    public override void SomeAction()
    {
        Console.WriteLine("A!");
        base.SomeAction();
    }
}
TrueWill
A: 

You do not need to check types to do what you want to do. You should look at Visitor pattern. You can find all information about it in GoF book or at www.dofactory.com, but let me explain my point:

Your external class will implement IVisitor interface that will have methods DoDerivedA(), DoDerivedB and DoDerivedC. After that you should add to BaseClass virtual function that will use your external class:

public virtual void DoExternal(IVisitor v){}

DerivedA will override this method like that:

v.DoDerivedA();

After that you`ll have something like that in your External:

AcceptBaseByExternal(BaseClass derivedInstance)
{
  derived.DoExternal(this);
}

This will do anything you want according to the actual class type. All you need is create a specific method for every derived class.

When I wrote it I also thought that you could create one method in your ExternalClass instead of single method for single derived class and parametrize it with some parameter. E.g. implement virtual function in BaseClass that returns enum and every derived should override that enum so that ExternalClass know what code it should execute.

Yaroslav Yakovlev
A: 

IF you're looking to differentiate explicitly between the parent/derived class, IMO, that is an indication to review the design. Used correctly, the derived class should be directly substitutable.

Use a virtual function instead .

Everyone
A: 

switch has its place in OOP - where an object can change its state and the current action is based on its present state.

Most of the time, switch is misused. If you ever find you are using switch on a value which remains constant within your object then you should probably be using polymorphism.