为什么可以';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#无法解决这个问题?从建筑学的角度来看,我正在做的事情是疯狂的吗?我试图理解为什么(我知道这可以通过铸造来解决)
编辑
当我引入interfaceC
时,问题就出现了。当我使用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.