Why can't .Net / C # understand the inheritance of interfaces with properties of the same name?

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; } } 

It 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(); } 

It looks good, but it will not compile. This gives me an Ambiguity exception:

Screenshothot compiler

Why can't C # understand this? Am I crazy from an architectural point of view? I am trying to understand why (I know that this can be solved by casting).

EDIT

Problems arose when I introduced the C interface. When I use MyClass : A, B , I have no problem at all.

FINAL

Just designed a blog about the topic: Ambiguity of the interface and implicit implementation .

+6
inheritance c # interface ambiguity
source share
8 answers

In short, because it is ambiguous.

Now a more detailed story. As you have already seen, there is an explicit implementation of the interface, so you can have two different implementations for A.Property and B.Property, and when you have only C, you cannot tell whether the implementations are the same or not. Since the C # “philosophy” should not guess what you had in mind, but forcing you to specify it more clearly when necessary, the compiler does not select either A.Property or B.Property, but reports an error.

+7
source share

You need an explicit implementation of the interface :

 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 the time comes to call them, you will need 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 that this is a bad design, if you are going to open the C interface, make sure you find the best way to open A / B.Property.

+4
source share

What do you need to find out? cTest is of type “C” and it inherits “Property” from two different classes; the compiler does not know which one you want. This behavior is inherited from C ++; This is a classic example of “why multiple inheritance is Pandora’s box.”

Other object-oriented languages ​​- Java is a great example - avoid this problem by definition: methods named-like / like-signatured are merged into a common descendant.

+3
source share

When you inherit a single interface, the compiler can determine exactly which method you want to implement when adding a new method.

However, when multiple interfaces have the same method, the basic (and correct) assumption is that each interface expects a DIFFERENT implementation for this method because these 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 the two interfaces have the same NAME for the property or method is arbitrary - there is no reason to assume that they share something OTHER and then the name, so the compiler protects you from an error implicitly treating them in the same way.

+3
source share

It is not easy, and it also does not look easy. In the event of a name collision between two interfaces, .NET should ask you which interface you are trying to implement. His way of asking you this is through an ambiguity mistake.

If you did not have such errors, you could accidentally implement the interfaces.

+2
source share

you need explicity to implement both properties from each interface:

 public class MyClass : C { string A.Property { get; set; } string B.Property { get; set; } } 
+2
source share

Because you are doing wrong. A and B collide and have the same name for the property ... you need to use the implementation of the Explicit interface implementation.

Link here .

0
source share

There are many answers, and they are all right, since an explicit implementation of the interface is the answer to your problem.

I will try to clarify the motivation for this design with a somewhat confusing example:

Say I have an interface for people who are starting up (with possible implementations like LongDistanceRunner , Jogger , MarathonMan , etc.)

 public interface IRunner { void Run(); } 

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

 public interface IRunnable { void Run(); } 

Now I want to create an interface for IMusicallJogger (implementations such as 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 he start running around the park, or should he turn on the boombox, or both, or something else? If I implement both a class and callsite, it may be obvious that I want my joggers to do both, but what if I control only callsite? But what if there are other implementations of the interface that do something else? And what if my runner starts running around the park when he is used in a context where he is seen as a device (via casting).

Where the explicit implementation of the interface is implemented.

I need to define my class as follows:

 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 indicate which 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.

0
source share

All Articles