Can a child class implement the same interface as

2020-03-01 06:47发布

问题:

I've never encountered this issue before today and was wondering what convention/best practice for accomplish this kind of behavior would be.

Basic setup is this:

public interface IDispatch {
    void Dispatch();
}

public class Foo : IDispatch {
    void IDispatch.Dispatch() {
        DoSomething();
    }
}

public class Bar : Foo {
     ...
}

Bar needs to subclass Foo because it shares all the same properties as Bar plus introduces 2 new ones that I need to encounter for. The problem I have is that Foo also needs a slightly different implementation of Dispatch(). Normally it would be overridden but thats not valid for an interface method so is it fine to just have Bar implement IDispatch as well so my class definition looks like this:

public class Bar : Foo, IDispatch { .... }

and then just do an explicit implementation of that interface method in Bar as well? My compiler doesn't seem to complain when I try to do it this way but I wasn't sure if it would cause any runtime issues resolving which implementation to use down the road or if there was a better way to accomplish something like this.

Also worth mentioning that at my workplace we use code generation from UML models which enforces that all class design must be done from a model first. The code generation tool is what causes interface methods to be implemented explicitly (don't want to debate the pros and cons of this its just what I'm forced to deal with right now so having an implicit implementation is not an option)

回答1:

You could, alternatively, do this one of two ways:

First, don't implement the interface explicitly:

public class Foo : IDispatch {
    public virtual void Dispatch() {
        whatever();
    }
}

public class Bar : Foo {
    public override void Dispatch() {
        whateverElse();
    }
}

Second, implement it explicitly but add a function that the child class can override:

public class Foo : IDispatch {
    void IDispatch.Dispatch() {
        this.Dispatch();
    }

    protected virtual void Dispatch() {
        whatever();
    }
}

public class Bar : Foo {
    protected override void Dispatch() {
        whateverElse();
    }
}


回答2:

Yes, you can explicitly redeclare that you want to implement IDispatch, and implement it explicitly again in Bar.

However, you won't be able to call the original implementation in Foo. If you need to do that, you'll need to change Foo either to use implicit interface implementation with a virtual method (which can be overridden and then called with base.Dispatch() in Bar) or make the Foo implementation call a protected virtual method which again you'd override in Bar.



回答3:

Bar already implements IDispatch if it is subclass of Foo, no need to explicitly state that. If you want to implement only one method of interface in a different way, do sth like this:

IDispatch { void Method(); }
Foo : IDispatch { public virtual void Method() { implementation1 } }
Bar : Foo { public override void Method() { implementation2 } }


回答4:

You don't have to do the IDispatch.Dispatch - so long as a method called Dispatch is in your class you will have implemented the interface.

You can do this, it builds for me:

  public class Foo : IDispatch
  {
    public virtual void Dispatch()
    {
    }
  }
  public class Bar : Foo
  {
    public override void Dispatch()
    {
      base.Dispatch();
    }
  }


回答5:

I do prefer to explicitly implement interfaces. It's easier for people unfamiliar with your code base to understand what's an interface vs class specific logic.

You can still accomplish class inheritance while explicitly implementing interfaces. You just need to have the base class implement the interface, and have that implementation call into a virtual function which can be extended. Here's an example:

interface Inter
{
    void Call();
}

class A : Inter
{
    //Explicitly implemented interface
    void Inter.Call()
    {
        this.Call();
    }

    public virtual void Call() { Console.WriteLine("Base call in A"); }
}

class B : A
{
    public override void Call()
    {
        Console.WriteLine( "Called B" );
    }
}

class Program
{
    static void Main( string[] args )
    {
        var a = new A();   //Base class
        var aa = (Inter)a; //Interface only
        a.Call();
        aa.Call();

        var b = new B();   //Child class
        var bb = (Inter)b; //Interface only of Child class
        b.Call();
        bb.Call();

        //See the output before the console program closes
        Console.ReadLine();         
    }
}

Program output:

Base call in A
Base call in A
Called B
Called B