跳到主要內容

介面繼承 明確實作(Explicitly Implement Interface Members)


相信許多人在使用地表最強IDE Visual Studio 來繼承實作介面(Interface)成員的時候,旁邊的

小燈泡在提示實作的同時也會提示明確實作。

很多時候我們選擇忽略這個提示繼續實作我們必須實作的成員,但總有一天該逃的總是逃不

過,所以到底什麼是明確實作?

一言以蔽之,明確實作成員會透過該介面個體進行存取呼叫。



 public interface IAnimal
    {
        string Name { get; set; }
        void Voice();
    }
    public class Dog : IAnimal
    {
        public string Name { get; set; }

        public void Voice()
        {
            Console.WriteLine("有狗發出聲音");
        }
        void IAnimal.Voice()
        {
            Console.WriteLine("有動物發出聲音");
        }
        static void Main(string[] args)
        {
            var dog = new Dog();
            dog.Voice();             // output 有狗發出聲音
            ((IAnimal)dog).Voice();  // output 有動物發出聲音
            Console.ReadKey();
        }
    }

從上方的程式碼中看到同一個個體實例在不同的形態下做的事情不一樣,Dog沒辦法呼叫

IAnimal.Voice,只有當Dog是IAnimal時才可以呼叫專屬於IAnimal的明確實作Voice。

這樣有什麼好處?

代表著我們能夠依照同一個個體因實際狀況的不同去去做不一樣的事,甚至是不同型態的回傳與參數也都能辦到(如下方)。

public class Dog : IAnimal
    {
        public string Name { get; set; }
        public string Voice()
        {
            return ($"有{this.Name}發出聲音");
        }
        void IAnimal.Voice()
        {
            Console.WriteLine(this.Voice());
        }

        static void Main(string[] args)
        {
            var dog = new Dog() { Name = "法國鬥牛犬"};
             dog.Voice();             
            ((IAnimal)dog).Voice();  
            Console.ReadKey();
        }
    }

當然也能在明確實作與實作並存的情況下我們要讓他做一樣的事,利用明確實作區隔讓物件再強型態時執行效率更好的存取。




除此之外還有什麼樣的用法呢?



當一個物件繼承兩個擁有時相同成員,我們也能用明確實作去區隔他們在不同介面個體的情況下做不一樣的事。

    public interface IAnimal
    {
        string Name { get; set; }
        void Voice();
    }
    public interface IDog
    {
        string Name { get; set; }
        void Voice();
    }
    public class Dog : IAnimal, IDog
    {
        public string Name { get; set; }
        public void Voice()
        {
            Console.WriteLine($"{Name}在叫");
        }
        void IAnimal.Voice()
        {
            Console.WriteLine("有一個動物在叫");
        }
        void IDog.Voice()
        {
            Console.WriteLine("有一隻狗在叫");
        }

        static void Main(string[] args)
        {
            var dog = new Dog() { Name = "法國鬥牛犬"};
             dog.Voice();               // output 法國鬥牛犬在叫
            ((IAnimal)dog).Voice();    // output 有一個動物在叫
            ((IDog)dog).Voice();      // output 有一隻狗在叫
            Console.ReadKey();
        }
    }



有時候在實作成員的時候難免被簽章所束縛感到不便,或是依照實際運作的不同,我們需要

改變方法的行為,明確實作的確大幅提升了介面實作成員使用上的彈性,但要小心的是,當

明確實作的方法與派生類別內的同名成員做的事差異太大時,難免會讓要接你的程式碼的同

事阿明或小王混亂,所以明確實作的規劃還是必須多多考慮!


留言

這個網誌中的熱門文章

C# 委派(Delegate) (一)

今天要介紹的是C#的委派 Delegate Delegate的發展由函數指標( funtion pointer )而來,可以說Delegate是函數指標中的語法糖( Syntactic sugar )也不為過,在Java中則是Sam類。早期在C# 1.0的時候,匿名函數與Lambda表達式還沒有被發展出來,C與C++有函數指標來負責打包函數( function ),那C#呢?我們都知道物件導向程式OOP中所有的東西都該是物件,所以C#就創造了一個類別專門來打包函數。 本篇開始會依序從C#的發展順序介紹委派 Delegate、Anonymous Function、 Lambda  Expression、Func<>、Action<> 委派含括很大的範圍,故可能會花上幾篇的篇幅來一一介紹。   1.Delegate 首先來介紹的是最初的委派( Delegate )。月亮是外國的圓,我們先來看看微軟( MicroSoft )怎麼介紹自家的的委派-- A delegate is a reference type that can be used to encapsulate a named or an anonymous method -- 一種用來封裝具名或匿名方法的參考 類型 。至於為什麼封裝函數叫做委派呢,不如試想,原本有一個流程方法(Sop)是要由A公司去完成的,但我們將他外包給委派給B公司去做,把方法流程外包的行為就叫做委派,這樣不難理解吧。 廢話不多說,立刻來看委派是如何被宣告( declare )以及使用的。 委派的宣告: public delegate int MyDelegete(int x); 我們可以注意到一個委派類型的宣告簽章( Signatures ),就像是類似宣告一個方法般,給他回傳型態、名稱、參數就完成宣告了,所以我們先做的是宣告一個回傳型態為int、委派類型名稱為Mydelegate、參數型態為int的委派宣告。好啦,宣告完成拉接下來是封裝方法。既然委派是一種類型,所以我們必須將他實作( implement )。 挖哩怎麼報紅了,原來委派類型變數的宣告必須在建構子參數中給與這個符合此委派類型簽章的方法,於是我們必須相應而生出一個回傳型態、參數型態皆

C# 委派(Delegate) (二) - Anonymous Function、Lambda Expression

上一篇中 C# 委派(Delegate) (一) 介紹了Delegate類基本觀念、宣告方式與使用方式,本篇將照著C#中委派的發展史中,繼續介紹 Anonymous Function、Lambda Expression。 Anonymous Function 還記得上篇的範例中,我們每宣告一個委派( delegate )的變數( variable )就要寫一個跟委派相同簽章的 具名 方法對應是吧? 但是這個專用來給委派變數宣告用 具名 方法, 具名 不是顯得很多餘嗎,我們似乎不太需要知道這個方法叫什麼名字啊。 public delegate int MyDelegate(int x); static void Main(string[] args) { //AddOne是專門寫來給委派變數使用的方法,這個具名方法只用一次,從此以後AddOne沒在被用過。 MyDelegate mydelegate = new MyDelegate(AddOne); } public static int AddOne(int number) { return ++number; } 所以在C#2.0中貼心的微軟發展了一套專門給委派變數宣告專用的語法糖( Syntactic sugar )叫做匿名方法( Anonymous Function )。 public delegate int MyDelegate(int x); static void Main(string[] args) { //不需要再寫一個AddOne方法 MyDelegate mydelegate = delegate (int number) { return number + 1; }; } 所以在C#2.0中只要如上宣告就完成了委派變數的宣告。匿名方法的變數宣告中,左式必須要使用明確的委派類別來宣告(這邊使用 MyDelegate ),不能使用 var 關鍵字,如果堅持要使用var關

Reference Type & Value Type

相信有仔細看過前一篇文章後 對於C#中Value Type 與Ref  Type有了一些初步的了解(才怪) 今天直接 Passing By Value 與 Passing By Reference來探討Value Type 與Ref  Type的差別 話不多說舉個例子 1.參考型別(Reference Type) 假設某個學校出了一個模範生小明,老師希望以後所有的學生都像小明一樣聰明 所以把小明克隆了一個新的取名叫做小華 看以下程式碼 public static void Main() { var student1 = new Stutent(); student1.Name = "阿明"; var student2 = student1; student2.Name = "小華"; Console.WriteLine(student1.Name); } class Stutent { public string Name{get;set;} } 猜猜Output出什麼呢 答案是小華 什麼? 為什麼? 靠北不是把令了一個新的變數student2來裝student1了嘛 那為什麼把新生出來的student2的名字取為小華 導致原本的小明也變成小華了呢 老師感到疑惑,小明到底跑哪去了呢,聰明的老師立刻打開電腦 Google了Msdn才發現   阿~!  小華原來就是小明 還裝?! 因為  Class Student是一個 參考型別 參考型別的變數 承載的是記憶體的位置 將一個新的座位,指派給小明, 並把新座位的主人改名為小華, 然後在請原本小明座位上的人大聲喊出自己的名字 小明 當然就會說 "我是小華" 囉 仔細看看這段程式碼 var student1 = new Stutent(); 再把它中文翻譯 我宣告了一個變數student1 並指派為一個新的學生 口語邏輯上