[英]Can derived C# interface properties override base interface properties with the same name?
[英]Why can't .Net / C# understand interface inheritance with properties of the same name?
考慮以下類和接口:
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#不能解決這個問題? 從架構的角度來看,我在瘋狂嗎? 我試圖理解為什么 (我知道它可以通過鑄造來解決)。
編輯
當我介紹接口C
時出現了問題。 當我使用MyClass : A, B
我完全沒有問題。
最后
剛剛完成了一個關於這個主題的博客: 界面歧義和隱式實現 。
簡而言之,因為它確實很模糊。
現在更詳細的故事。 正如您已經看到的那樣,有明確的接口實現,因此您可以為A.Property和B.Property提供兩種不同的實現,當您只有C時,您無法判斷實現是否相同。 由於C#“哲學”不是猜測你的意思,而是讓你在必要時更清楚地表明它,編譯器不會選擇A.Property或B.Property,但報告錯誤。
您需要顯式接口實現 :
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; }
}
當打電話給他們時,你將不得不這樣做:
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。
有什么可以搞清楚的? cTest的類型為“C”,它從兩個不同的類繼承“Property”; 編譯器不知道你想要哪一個。 這種行為繼承自C ++; 這是“為什么多重繼承是潘多拉盒子”的典型例子。
其他面向對象語言 - Java是一個值得注意的例子 - 根據定義避免這個問題:like-named / like-signatured方法融合在一個共同的后代中。
當您從單個接口繼承時,編譯器可以確定在添加新方法時您想要實現哪種方法。
但是,當多個接口具有相同的方法時,基礎(和正確)假設是每個接口都需要該方法的不同實現,因為這些方法或屬性是在不同的接口上定義的。
因此,編譯器會告訴您這些不同的接口需要為每個屬性實現顯式實現。
兩個接口共享屬性或方法的相同NAME的事實是任意的 - 沒有理由假設它們共享除名稱之外的任何東西,因此編譯器保護您不會以同樣的方式隱式處理它們。
它並不簡單,也不簡單。 如果兩個接口之間發生名稱沖突,.NET需要詢問您嘗試實現哪個接口。 問你的方法是通過歧義錯誤。
如果你沒有這種錯誤,你最終會偶然實現接口。
你需要明確地實現每個接口的兩個屬性:
public class MyClass : C
{
string A.Property { get; set; }
string B.Property { get; set; }
}
因為你在做什么是不對的。 A和B發生沖突並且屬性具有相同的名稱...您需要使用顯式的接口實現。
參考這里 。
有很多答案,而且所有答案都是正確的,因為顯式接口實現是您問題的答案。
我將嘗試用一個有點復雜的例子來澄清這個設計背后的動機:
假設我有一個運行的人的界面(可能的實現,如LongDistanceRunner
, Jogger
, MarathonMan
等)
public interface IRunner
{
void Run();
}
以及可以打開和運行的設備接口(可能的實現BathTub
, Application
, Dishwasher
等)
public interface IRunnable
{
void Run();
}
現在我想為IMusicallJogger
創建和接口(像JoggerWithIpod
, BoomBoxJogger
等實現)
public interface IMusicalJogger : IRunner, IRunnable {}
public class BoomBoxJogger : IMusicalJogger
{
// code here
}
BoomBoxJogger bbJogger = new 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.
希望我幫助澄清這個概念。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.