7

Consider the following class and interfaces:

    public interface A { string Property { get; set; } }

    public interface B { string Property { get; set; } }

    public interface C : A, B { }

    public class MyClass : C
    {
        public string Property { get; set; }
    }

Looks simple, right? Now consider the following program:

    static void Main(string[] args)
    {
        MyClass myClass = new MyClass();
        myClass.Property = "Test";

        A aTest = myClass;
        B bTest = myClass;
        C cTest = myClass;

        aTest.Property = "aTest";
        System.Console.WriteLine(aTest.Property);
        bTest.Property = "bTest";
        System.Console.WriteLine(bTest.Property);
        cTest.Property = "cTest";
        System.Console.WriteLine(cTest.Property);
        System.Console.ReadKey();
    }

Looks okay, but it will not compile. It gives me an Ambiguity exception:

Screenshot compiler

Why isn't C# able to figure this out? Is what I'm doing crazy from an architectural point of view? I'm trying to understand the why (I know it can be solved with casting).

EDIT

The problems arose when I introduced interface C. When I use MyClass : A, B I've got no problems at all.

FINAL

Just finised a blog about the subject: Interface Ambiguity and Implicit Implementation.

Kees C. Bakker
  • 32,294
  • 27
  • 115
  • 203
  • Which would you *expect* it to call? – Cody Gray - on strike Apr 05 '11 at 12:00
  • Is this just something you are messing around with, or is this part of your design? – Nix Apr 05 '11 at 12:10
  • @Nix well... we've got some interfaces that have this problem. A and B are very small interfaces and C in a big one that needs to inherit A and B. – Kees C. Bakker Apr 05 '11 at 12:15
  • 2
    If the interfaces A and B have the same methods, why don't they inherit from an interface that contains these methods. This would get rid of your problem. – codymanix Apr 05 '11 at 12:25
  • @Codymanix yes! That's the money shot :-). – Kees C. Bakker Apr 05 '11 at 12:27
  • 1
    A more interesting question is why your code wouldn't work even if A's property was read-only and B's was write-only. It would seem having a read-only Property and a write-only Property shouldn't make reads or writes ambiguous, but the compiler squawks about ambiguity. – supercat Jul 17 '11 at 02:02

8 Answers8

8

In short because it's ambiguous indeed.

Now more detailed story. As you've already seen there is explicit interface implementation, so you can have two different implementations for A.Property and B.Property and when you have only C there is no way you can tell if implementations are the same or not. Since C# "philosophy" is not to guess what you meant, but make you state it more clear when necessary, compiler does not choose either A.Property or B.Property, but reports an error.

Konstantin Oznobihin
  • 5,234
  • 24
  • 31
  • +1 finally someone actually answered the question. Also I think the confusion comes from the fact that it is still considered ambiguous even when you don't explicitly implement the interfaces. – juharr Apr 05 '11 at 12:21
  • Almost: It doesn't really explain why `public class MyClass: A, B` works and `public class MyClass: C` does not. – rsenna Apr 05 '11 at 12:30
  • @rsenna... well... if A.Property == B.Property... there should have been an interface X that needs to be implemented by both A and B to show that Property comes from the same thing. – Kees C. Bakker Apr 05 '11 at 12:34
  • @Kees: Again, `public class MyClass: A, B` **WORKS**. That means the same `string Property { get; set; }` in class `MyClass` is able to implement both interfaces, and also means that you are wrong. The problem happens when we add a *third* interface `C`, inheriting from interfaces `A` and `B`. – rsenna Apr 05 '11 at 12:38
  • @rsenna... welll actually MyClass: C **works** as well... but ((C)myClass).Property doens't work. Because A.Property van B.Property are not guaranteed the same thing. On the class level it will work (implicit inheritance), but on the interface level (C) it won't work. – Kees C. Bakker Apr 05 '11 at 12:43
  • @Kees: Sorry, but what doesn't make sense IMHO is that interfaces are just *contracts*. There is no real code involved. Your reasoning would make sense if we were talking about real multiple inheritance (i.e. if this was about C++, and `A` and `B` were abstract classes). But we are talking about simple interfaces here: so there should be nothing wrong about the concrete class `MyClass`, even when it implements the interface `C`. The fact that that class *compiles* that way, and that the error just happens when a client code tries to cast the class to `C` just makes it worst. – rsenna Apr 05 '11 at 13:35
  • @rsenna... I think I'll write up a blog about why the choice of C# is correct. I'll share the link to that post. – Kees C. Bakker Apr 05 '11 at 13:46
  • @Kees: Conclusion: to me, the real answer to the OP's question is that the C# implementation is buggy, period. It is not a serious problem, and I could even accept that kind of "language design decision" if (and only if) an error were shown during `C` and/or `MyClass` compilation. – rsenna Apr 05 '11 at 13:46
  • 1
    @rsenna I've finished writing a blog posting about the subject. Please visit http://keestalkstech.blogspot.com/2011/04/interface-ambiguity-and-implicit.html for more information. – Kees C. Bakker Apr 08 '11 at 11:34
  • @Kees: I've just read it. I guess you did a very good job *explaining* the problem; but there is nothing in that post that explains *why* C# works in that particular way... You wrote "The compiler is able to figure out that the Size property is the implementation of both the IShippable and IAnimal interface". So, if the `Giraffe` class implements `IZooAnimal` **without errors**, then it follows that we **should be able to cast `Giraffe` to `IZooAnimal` also without errors**. That's my problem with the C# implementation, and that's why I think it does **not** make sense. – rsenna Apr 08 '11 at 15:41
  • I understand ambiguity squawk if there's more than one thing that could apply. Is there any reason, though, that if one has interfaces IReadableFoo with a getter for property "Foo", and IWritableFoo with a setter for property "Foo", one shouldn't be allowed to inherit both and have the system use the appropriate one? It's possible to shadow the get and set properties with a combined-get-set property, but that adds additional work for every implementation. Any idea why the system can't simply use the 'get' property for gets and 'set' for sets? – supercat Jul 17 '11 at 01:58
4

You need explicit interface implementation:

public interface A { string Property { get; set; } }

public interface B { string Property { get; set; } }

public interface C : A, B { }

public class MyClass : C
{
    string B.Property { get; set; }
    string A.Property { get; set; }
}

When it comes time to call them you are going to have to do:

MyClass c = new MyClass();
Console.WriteLine("Property A is ": ((A)c).Property);

Why don't you do:

public class MyClass : C
{
    string B.Property { get; set; }
    string A.Property { get; set; }
    string B { get { return B.Property; } set { B.Property=value; } }
    string A { get { return A.Property; } set { A.Property=value; } }

}

And it should be noted this is bad design, if you are going to expose an interface C, make sure you find a better way to expose A/B.Property.

Nix
  • 57,072
  • 29
  • 149
  • 198
3

What's to figure out? cTest is of type "C", and it inherits "Property" from two different classes; the compiler doesn't know which one you want. This sort of behavior is inherited from C++; it's the classic example of "why multiple inheritance is a Pandora's box."

Other object-oriented languages -- Java is a notable example -- avoid this problem by definition : like-named/like-signatured methods are fused in a common descendent.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
3

When you inherit from a single interface the compiler can determine exactly which method you are interested in implementing when you add the new method.

However when multiple interfaces have the same method, the underlying (and correct) assumption is that each interface expects a DIFFERENT implementation for the method, due to the fact that those methods or properties are defined on different interfaces.

So the compiler tells you that these different interfaces require an explicit implementation for each of these properties.

The fact that two interfaces share the same NAME for a property or method is arbitrary - there is no reason to assume that they share anything OTHER then the name, so the compiler protects you from making the mistake of implicitly treating them in the same way.

NightDweller
  • 913
  • 5
  • 8
2

It is not simple, and it doesn't look simple either. In case of a name collision between two interfaces, .NET needs to ask you which interface are you trying to implement. Its way to ask you this is via the ambiguity error.

If you didn't have this kind of errors, you would end up implementing interfaces by chance.

Daniel Daranas
  • 22,454
  • 9
  • 63
  • 116
  • 1
    I don't see the collision, because apparently both A and B use a property called Property. They can both use the same field. But as soon as I introduce interface C, I'm in trouble. – Kees C. Bakker Apr 05 '11 at 12:10
2

you need to explicity implement both properties from each interface:

public class MyClass : C     
{         
    string A.Property { get; set; }    
    string B.Property { get; set; }      
} 
Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
0

Because what you are doing is not right. A and B are clashing and have the same name for the property... you need to use Explicit implementation of interface.

Reference here.

Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • explicit implementation doesn't help when accessing through the interface, only when accessing through the class – Sam Holder Feb 15 '12 at 12:20
0

There are a lot of answers, and all of them are right, as explicit interface implementation is the answer to your problem.

I'll try to clarify the motivation behind this design with a somewhat convoluted example:

Let's say I have an interface for people that run (with possible implementations like LongDistanceRunner, Jogger, MarathonMan, etc)

public interface IRunner 
{
   void Run();
}

and an interface for devices that can be turned on and ran (with possible implementations BathTub, Application, Dishwasher, etc)

public interface IRunnable
{
   void Run();
}

Now I want to create and interface for a IMusicallJogger (implementations like JoggerWithIpod,BoomBoxJogger, etc)

public interface IMusicalJogger : IRunner, IRunnable {}

public class BoomBoxJogger : IMusicalJogger
{
   // code here
}

BoomBoxJogger bbJogger = new BoomBoxJogger();

Now, when I say bbJogger.Run() what should my object do? Should it start running across the park, or should it turn on the boombox, or both, or something else entirely? If I implement both the class and the callsite, it might be obvious that I want my joggers to do both, but what if I control just the callsite? And what if there are other implementations of the interface that do something else? And what if my jogger starts running across the park, when it's used in a context where it is considered like a device (through casting).

That's where explicit interface implementation comes into play.

I have to define my class like this:

public class BoomBoxJogger : IMusicalJogger
{
   void IRunner.Run() //implementation of the runner aspect
   {
      Console.WriteLine("Running through the park");
   }

   void IRunnable.Run() //implementation of the runnable aspect
   {
      Console.WriteLine("Blasting out Megadeth on my boombox");
   }

   public void Run() //a new method defined in the class itself 
   {
      Console.WriteLine("Running while listening to music");
   }

}

and then, when I call, I have to specify what aspect of my jogger I want to use:

BoomBoxJogger bbJogger = new BoomBoxJogger();
((IRunner).bbJogger).Run(); // start running
((IRunnable).bbJogger).Run(); // blast the boombox
//and of course you can now do
bbJogger.Run //running while listening

((IMusicalJogger)jogger).Run(); //compiler error here, as there is no way to resolve this.

Hope I helped clarify the concept.

SWeko
  • 30,434
  • 10
  • 71
  • 106
  • Thanks for the comment. The problem is not on the class level, but on the interface (C) level. When I have an interface C: A, B and I use that interface I get in trouble. Implicit inheritance will work on the object itself. – Kees C. Bakker Apr 05 '11 at 12:46
  • Yes, you are saying the equivalent of `IMusicalJogger.Run()`. What should the compiler do except raise his arms in anguish? If I omit the explicit implementations from the class, my app will behave non-intuively, but still run (pun intended). – SWeko Apr 05 '11 at 12:52
  • @Kees, btw, you can do `interface C: A, B { new string Property { get; set; }; }` but I think that makes the problem worse. – SWeko Apr 05 '11 at 13:00
  • Yeah, I think @Konstantin gave the best answer until now. Also @codymanix gives some good information about how to fix the problem. – Kees C. Bakker Apr 05 '11 at 13:03
  • @Kees: yes, but I like the example I came up with, I think I'll spin it into a blog post :) – SWeko Apr 05 '11 at 13:07