为什么可以';t.Net/C#了解同名属性的接口继承吗?

为什么可以';t.Net/C#了解同名属性的接口继承吗?,c#,.net,inheritance,interface,ambiguity,C#,.net,Inheritance,Interface,Ambiguity,考虑以下类和接口: 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; } } 看起

考虑以下类和接口:

    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; }
    }
看起来很简单,对吧?现在考虑下面的程序:

    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();
    }
看起来没问题,但无法编译。这给了我一个模糊的例外:

为什么C#无法解决这个问题?从建筑学的角度来看,我正在做的事情是疯狂的吗?我试图理解为什么(我知道这可以通过铸造来解决)

编辑

当我引入interface
C
时,问题就出现了。当我使用MyClass:A,B时,我一点问题都没有

决赛


刚刚完成了一篇关于这个主题的博客:。

它并不简单,看起来也不简单。如果两个接口之间发生名称冲突,.NET需要询问您要实现哪个接口。问你这个问题的方式是通过歧义错误

如果没有此类错误,那么最终可能会偶然实现接口。

您需要:


当需要给他们打电话时,你必须:

MyClass c = new MyClass();
Console.WriteLine("Property A is ": ((A)c).Property);
你为什么不:

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

}
需要注意的是,这是一种糟糕的设计,如果要公开接口C,请确保找到更好的方法公开a/B.Property。

您需要从每个接口中同时显示两个属性:

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

要弄清楚什么?cTest是类型“C”,它从两个不同的类继承“Property”;编译器不知道您想要哪一个。这种行为是从C++继承的;这是“为什么多重继承是潘多拉魔盒”的经典例子


其他面向对象语言(Java是一个显著的例子)通过定义避免了这个问题:like-named/like-signatured方法融合在一个公共子代中。

因为您所做的是不对的。A和B发生冲突,并且具有相同的属性名称。。。您需要使用接口的显式实现


参考。

简而言之,因为它确实模棱两可


现在是更详细的故事。正如您已经看到的,有显式的接口实现,因此对于A.Property和B.Property可以有两种不同的实现,当您只有C时,您无法判断实现是否相同。由于C#“哲学”不是猜测您的意思,而是在必要时让您更清楚地说明它,编译器不会选择A.Property或B.Property,而是报告错误。

当您从单个接口继承时,编译器可以准确地确定您在添加新方法时感兴趣实现的方法

但是,当多个接口具有相同的方法时,基本的(正确的)假设是,由于这些方法或属性是在不同的接口上定义的,因此每个接口期望该方法具有不同的实现

因此,编译器告诉您,这些不同的接口需要这些属性中的每一个的显式实现


两个接口共享一个属性或方法的相同名称这一事实是任意的——没有理由假定它们共享名称以外的任何内容,因此编译器可以防止您犯以相同方式隐式处理它们的错误。

有很多答案,所有答案都是正确的,因为显式接口实现是问题的答案

我将尝试用一个有点复杂的例子来阐明这种设计背后的动机:

比如说,我有一个供跑步者使用的界面(可能的实现方式有
LongDistanceRunner
Jogger
MarathonMan
,等等)

以及一个可开启和运行的设备接口(可能的实现方式有
浴缸
应用程序
洗碗机
,等等)

现在我想为
IMusicallJogger
(像
JoggerWithIpod
BoomBoxJogger
等实现)创建一个接口

现在,当我说
bbJogger.Run()
我的对象应该做什么?它应该开始穿越公园,还是应该打开吊杆盒,或者两者都打开,或者完全其他什么?如果我同时实现类和调用站点,很明显我希望我的慢跑者同时实现这两个功能,但是如果我只控制调用站点呢?如果接口的其他实现做了其他的事情呢?如果我的慢跑器开始跑过公园,当它被用于一个被认为是一个装置(通过铸造)的环境中时会怎么样

这就是显式接口实现发挥作用的地方

我必须这样定义我的类:

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

}
然后,当我打电话时,我必须指定我想要使用的慢跑者的方面:

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.

希望我能帮助澄清这个概念。

+1但是OP仍然需要演员。这并不能真正回答“为什么?”。吹毛求疵:不会编译。删除public,因为它是一个显式接口实现……我在尝试执行以下操作时仍然存在问题:C test=new MyClass();Console.WriteLine(test.Property)-1显式实现在通过接口访问时没有帮助,只有在通过类访问时才有帮助。你希望它调用哪一个?这只是你在胡闹的东西,还是你设计的一部分?@Nix好吧。。。我们有一些接口有这个问题。A和B是非常小的接口,C是需要继承A和B的大接口。如果接口A和B具有相同的方法,为什么它们不从包含这些方法的接口继承。一个更有趣的问题是,为什么即使A的属性是只读的,B的属性是只读的,代码也不能工作。它似乎有一个只读属性和一个只读属性,不应该使读或写变得模棱两可,但是编译器会抱怨模棱两可。我仍然有一个
public interface IRunnable
{
   void Run();
}
public interface IMusicalJogger : IRunner, IRunnable {}

public class BoomBoxJogger : IMusicalJogger
{
   // code here
}

BoomBoxJogger bbJogger = new BoomBoxJogger();
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");
   }

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