Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple inheritance from the same interface in C#

Tags:

Please consider the following program:

using System;

public interface IFoo
{
    void DoFoo();
}

public class Bar: IFoo
{
    public void DoFoo() => Console.WriteLine("BAR!");
}

public class Baz: Bar, IFoo
{
    void IFoo.DoFoo() => Console.WriteLine("baz!");
}

class Program
{
  static void Main()
  {
    Baz baz = new Baz();
    baz.DoFoo();
    
    IFoo foo = baz;
    foo.DoFoo();
    
    Bar bar = baz;
    bar.DoFoo();
    
    IFoo foobar = bar;
    foobar.DoFoo();
  }
}

It gives the following output which I personally with my C++ background consider highly unexpected:

BAR!
baz!
BAR!
baz!

Having , IFoo in the declaration of Baz seems to be substantial, because otherwise void IFoo.DoFoo() doesn't compile.

Can someone please explain what is going on here (especially the last line)? And what should be done to prevent such behavior in real life? Should one avoid implementing from the same interface at all or there are some other rules to avoid problems?

UPD:

Looks like the principal problem here is not with "multiple inheritance" (which is not real multiple inheritance actually), but with the way interface methods can be implemented in C#. Namely, one can have two different implementations of the same method in the same class, one of which is explicit, another is implicit. E.g. this program:

using System;

public interface IFoo
{
    void DoFoo();
}

public class Bar: IFoo
{
    void IFoo.DoFoo() => Console.WriteLine("Foo!");
    public void DoFoo() => Console.WriteLine("BAR!");
}

class Program
{
  static void Main()
  {
    Bar baz = new Bar();
    baz.DoFoo();
    
    IFoo foo = baz;
    foo.DoFoo();
  }
}

prints

BAR!
Foo!

The trick with "multiple inheritance" just allows to introduce the explicit implementation from a derived class.

From my point of view this feature of C# is potentially dangerous, because if one implements a method of an interface, one usually expects the same method will be called no matter if it is invoked from the interface or from the class. And this is really the case if one implements everything only explicitly or only implicitly. But if both ways are used, this assumption is broken. So the moral seems to be:

  1. Don't mix implicit and explicit implementation of the same method if you don't have in mind to employ this strange effect for some purpose.
  2. Use explicit implementation in derived classes with caution.
like image 663
aparpara Avatar asked Dec 28 '21 13:12

aparpara


People also ask

Can we do multiple inheritance in interface?

By interface, we can support the functionality of multiple inheritance. It can be used to achieve loose coupling.

Can C support multiple inheritance?

Master C and Embedded C Programming- Learn as you go So the class can inherit features from multiple base classes using multiple inheritance. This is an important feature of object oriented programming languages such as C++.

Why is multiple inheritance not a problem in interface?

Java supports multiple inheritance through interfaces only. A class can implement any number of interfaces but can extend only one class. Multiple inheritance is not supported because it leads to deadly diamond problem.

Why is multilevel inheritance not supported in C?

C# does not support multiple inheritance , because they reasoned that adding multiple inheritance added too much complexity to C# while providing too little benefit. In C#, the classes are only allowed to inherit from a single parent class, which is called single inheritance .


1 Answers

This is a difference in the explicit implementation (void IFoo.DoFoo()) vs the implicit implementation (public void DoFoo()). The compiler will use the explicit implementation first. If you provide both an explicit and implicit implementation then the difference becomes clear:

https://dotnetfiddle.net/7l9gIs


using System;

public interface IFoo
{
    void DoFoo();
}

public class Bar: IFoo
{
    public void DoFoo(){ Console.WriteLine("BAR!"); }
}

public class Baz: Bar, IFoo
{
    void IFoo.DoFoo(){ Console.WriteLine("baz explicit!"); }
    public new void DoFoo(){ Console.WriteLine("baz implicit!"); }
}

public class Program
{
  public static void Main()
  {
    Baz baz = new Baz();
    baz.DoFoo();
    
    IFoo foo = baz;
    foo.DoFoo();
    
    Bar bar = baz;
    bar.DoFoo();
    
    IFoo foobar = bar;
    foobar.DoFoo();
  }
}

Output

baz implicit!
baz explicit!
BAR!
baz explicit!
like image 115
Erik White Avatar answered Sep 30 '22 17:09

Erik White