2

If a class implements an interface from two separate interfaces, does it behave exactly as if it implements it only once?

Example:

public interface IAnimal { /* ... */ }
public interface IFullAnimal : IAnimal { /* ... */ }

public interface IBear : IAnimal { /* ... */ }
public interface IFullBear : IBear, IFullAnimal { /* ... */ }

// and implementing IFullBear:
public class FullBear : IFullBear { /* ... */ }

Above, FullBear implements IAnimal from both IFullAnimal and IBear through IFullBear. Does this introduce any weird behavior concerning the implementation of IAnimal since both IFullAnimal and IBear do not provide any information about the implementation of IAnimal (as the language does not allow that).

J Balvin
  • 33
  • 1
  • 6
  • What about `interface IA { } interface IB : IA { } interface IC : IA, IB { }`. What would any of this have to do with the implementation? You're making multiple promises that the class has the members `IAnimal` promises. OK. – 15ee8f99-57ff-4f92-890c-b56153 Nov 09 '17 at 19:26
  • 3
    `IFullBear` does not *implement* anything, it is an interface. – crashmstr Nov 09 '17 at 19:29
  • So, you are saying: multiple promises that "whatever implements me must implement `IAnimal`" cannot potentially lead to multiple implementations of a method/property declared in `IAnimal`? – J Balvin Nov 09 '17 at 19:31
  • 2
    Where would the multiple implementations come from? A class implements the interface or it doesn't. Why would the designers of the language design it that way? And why would the compiler be absolutely silent about something so easy to detect? – 15ee8f99-57ff-4f92-890c-b56153 Nov 09 '17 at 19:39
  • 1
    Don't get this mixed up with C++ multiple inheritance. C# forbids inheritance from multiple classes specifically so there can't be multiple conflicting implementations in the same class, specifically to prevent the C++ diamond inheritance problem. – 15ee8f99-57ff-4f92-890c-b56153 Nov 09 '17 at 19:43

2 Answers2

4

In .NET, if IA and IB both inherit from IX and a class implements both, there is no distinction made between members of "the IX inherited by IA" and those of "the IX inherited by IB". All such members are simply members of IX. Further, there would be no distinction between a class which is declared as implementing IA, IB, and IX, versus one that is only declared as implementing IA and IB, since any class that implements IA, IB, or both will necessarily implement IX as well, whether or not it is declared as doing so.

The .NET model of interface inheritance avoids the "diamond problem" since mid-level interfaces cannot add anything to inherited interfaces that would distinguish them from any other inherited versions of those same interfaces. Java's model used to also avoid the diamond problem, but by allowing mid-level interfaces to declare default methods later versions of Java make deadly-diamond hierarchies possible.

supercat
  • 77,689
  • 9
  • 166
  • 211
4

No, and this is a very common and harmless scenario. System.Collections.Generic namespace is a great example of similar "redundant" interface declarations:

 public class List<T> : IList<T>, 
                        System.Collections.IList,
                        IReadOnlyList<T>

Both IList<T> and IReadOnlyList<T> evidently implement IEnumerable<T> and the world hasn't ended.

Don't confuse this with interface reimplementation, which does change behavior:

interface IFoo
{
    void Foo();
}

class Base: IFoo
{
     public void Foo() { Console.WriteLine("Base Foo!");
}

class Derived: Base { }

class DerivedWithATwist: Base, IFoo //redeclares interface
{
    void IFoo.Foo() { Console.WriteLine("Derived Foo!");
}

And now,

IFoo foo = new Base();
IFoo derived = new Derived();
IFoo derivedWithATwist = new DerivedWithATwist();

foo.Foo(); //Base Foo!
derived.Foo(); //Base Foo!
derivedWithATwist.Foo(); //Derived Foo!
(derivedWithATwist as Base).Foo(); //Base Foo!  !!!
InBetween
  • 32,319
  • 3
  • 50
  • 90