Inheritance and service class

2019-08-22 06:03发布

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.

3条回答
太酷不给撩
2楼-- · 2019-08-22 06:32

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.

查看更多
smile是对你的礼貌
3楼-- · 2019-08-22 06:42

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(Animal a) { ... }
void doStuff(Dog d) { ... }

and so on.

查看更多
爷、活的狠高调
4楼-- · 2019-08-22 06:55

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++".

查看更多
登录 后发表回答