开发者

Inheritance and service class

It's, I think somethin basic in OOP :

Environment : C#/.net 2.0

Let's say I have two class :

public class Animal
{

}
public class Dog : Animal
{

}

A service class with two method :

 public void DoStuff(Animal animal)
    {
        Console.Write("Animal stuff");
    }
    public void DoStuff(Dog animal)
    {
        Console.Write("Dog stuff");
    }
开发者_开发知识库

If I execute the following code :

 Animal instance = new Animal();
        MyService.DoStuff(instance);

        Animal instance2 = new Dog();
        MyService.DoStuff(instance2);

"Animal stuff" is printed twice.

So my question is : why ? And how can I get "Animal stuff" and "Dog stuff" without casting instance2, or moving the method from my service to my class (in fact I would like that my code works, but it's not :()

Thanks

PS : These are just example :)


Because the Visitor pattern is not really appealing, I'll just move my service's method to my class, waiting for a better solution.


You aren't overriding the doStuff() method in Dog, because the parameter type is different. They're two separate methods.

Either change the signature in Dog to match Animal or create a Visitor that sorts it out for you.

Here's one way to write it:

public interface Animal {  void accept(AnimalVisitor visitor); }

public class AbstractAnimal : Animal
{
    public void accept(AnimalVisitor visitor) { visitor.visit(this); } 
}

public class Dog : AbstractAnimal {}

public class Cat : AbstractAnimal {}

public interface AnimalVisitor
{
    void visit(Animal animal);
    void visit(Dog dog);
    void visit(Cat cat);
}

Now the service (and all others) can implement AnimalVisitor and do different things to each Animal subtype.

It's a common pattern called "double dispatch"; you can read more about it in Scott Meyers' "More Effective C++".


The reason is that the second call, although passing a Dog, is passing a reference to an animal. That reference can be any type of animal (you just happen to have passed a Dog) but .NET does not know that so it must call the version of the method that accepts a reference to an Animal rather than the more specific reference.


Another thing which might seem a hack is to cast the passed parameter to dynamic. This would let you implement a 'dynamic visitor', so that for example you would write

foreach (dynamic a in animals)
  doStuff(a);

void doStuff(Cat c) { ... }
void doStuff(Dog d) { ... }

and so on. This lets you avoid the 'double dispatch' approach completely because you're using dynamic dispatch instead. Please be aware that this approach is much more computationally intensive and might be infeasible in some (e.g., iterative) scenarios.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜