Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Normally I do this:

if (Animal is Dog)
{
    Doc d = (Dog)Animal;
    // d. etc..
} 
else if (Animal is Cat) 
{
    Cat c = (Cat)Animal;
    // c. ....
}

Is this a good way or are there better ways to implement this code above (performance, ...) ?

Should it be like this?:

Dog d = Animal as Dog;

if (d != null;)
{
    // d. etc..
} 
else if (Animal is Cat) 
{
    Cat c = (Cat)Animal;
    // c. ....
}

Or maybe like this?:

Dog d = Animal as Dog;
Cat c;

if (d != null;)
{
    // d. etc..
} 
else if ((c = Animal as Cat) != null) 
{
    // c. ....
}

Or maybe something else?

share|improve this question
add comment

3 Answers

up vote 26 down vote accepted

Ideally, you should aim for just:

Animal.DoWhateverYouNeedDone();

That is, implement the polymorphic behavior (if it's a dog, do a dog thing, if it's a cat, do a cat thing, etc.) in the classes themselves. So instead of this:

if (Animal is Dog) {
    var d = Animal as Dog;
    d.Bark();
}
if (Animal is Cat) {
    var c = Animal as Cat;
    c.Meow();
}

Do this:

Animal.Speak();

// where:

public class Dog: Animal {
    public void Speak() {
        this.Bark();
    }
    // ---- snip -----
}
public class Cat: Animal {
    public void Speak() {
        this.Meow();
    }
    // ---- snip -----
}
share|improve this answer
    
Exactly! This is the definition itself of polymorphism. –  Florian Margaine Jun 14 '13 at 9:37
    
+1 Specifically for the first thing you said. If you care what type you should only accept that specific type or its subtypes in the majority of circumstances. –  Rig Jun 14 '13 at 10:16
    
This is true, but sometimes you can't (I have one example where the classes exist in a library, which doesn't have access to other classes that would be needed by the method), and you haven't answered the question for those cases. –  pdr Jun 14 '13 at 10:32
2  
@pdr: Of course there are cases where this doesn't work, and the cause is usually bad design - either on your own part, or in a library you're using. When that happens, and you can't change the design, use whatever works, but by all means, wrap the ugliness in a sane wrapper and expose only that to other code. –  tdammers Jun 14 '13 at 10:34
1  
@pdr: wouldn't you then be serializing your messages anyway, and parse them back out on the other end? You can easily reintroduce the polymorphism while parsing, and you'll still have what boils down to a switch statement in a factory method, but at least you're not dispatching on an object's run-time type. I'd even argue that if you are passing objects around directly (e.g. using shared memory), it would still be more elegant to give them a property to report what kind of message they are and dispatch based on that. –  tdammers Jun 14 '13 at 13:23
show 2 more comments

tdammers answer is the correct way to do it, and 99% of the time you should do it that way.

very occasionally there maybe situations when you don't want to do it that way. In these circumstances I'd use the 'as and check for null' approach. Indeed FxCop will actually warn you that you are casting twice (once with is and once with an actual cast) in your first approach

share|improve this answer
1  
good answer with the FxCop link –  juFo Jun 14 '13 at 11:55
add comment

It rather depends on what behaviour you're trying to access. Expounding on your previous example:

        if (Animal is Dog)
        {
            Dog d = (Dog)Animal;
            d.BuryBone();
        }
        else if (Animal is Cat)
        {
            Cat c = (Cat)Animal;
            c.DrinkSaucerOfMilk();
        }

This is perfect if you're after dog or cat specific behaviour. Otherwise if you want to use the more general methods of the base class:

Animal.EatFood();

Or if you've defined an interface:

IAnimal tiddles = new Cat();           
IAnimal rex = new Dog();

tiddles.EatFood();
rex.EatFood();
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.