簡體   English   中英

為什么.Net / C#不能理解與同名屬性的接口繼承?

[英]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發生沖突並且屬性具有相同的名稱...您需要使用顯式的接口實現。

參考這里

有很多答案,而且所有答案都是正確的,因為顯式接口實現是您問題的答案。

我將嘗試用一個有點復雜的例子來澄清這個設計背后的動機:

假設我有一個運行的人的界面(可能的實現,如LongDistanceRunnerJoggerMarathonMan等)

public interface IRunner 
{
   void Run();
}

以及可以打開和運行的設備接口(可能的實現BathTubApplicationDishwasher等)

public interface IRunnable
{
   void Run();
}

現在我想為IMusicallJogger創建和接口(像JoggerWithIpodBoomBoxJogger等實現)

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM