我是誰?[C#]

來源:互聯網
上載者:User

我是誰?[C#]

 

Written by Allen Lee

 

0. xuzicn 提出了這樣一個問題:

有一個 interface ABC 包括了如下的方法 M():

public   interface  ABC
{
     void  M();
}

另外有個類 Class1 繼承了 ABC 並且擁有自己的方法 N():

public   class  Class1 : ABC
{
     public  Class1() {}

     public   void  M()
     {
        Console.WriteLine( " Now we are in Class1, using method which inherit from Interface ABC  " );
    }

     public   void  N()
     {
        Console.WriteLine( " Now we are in Class1, we used method which not inherit from Interface ABC  " );
    }
}

程式中有如下語句:

//  Code #01

ABC t  =   new  Class1();
t.M();

這種情況下編譯可以通過而且會輸出正確的結果。但是如果是下面的情況:

//  Code #02

ABC t  =   new  Class1();
t.N();

編譯就會出錯,所以通過 ABC t = new Class1() 這句話我們得到的肯定不是 Class1 的一個執行個體。但是介面是不可以執行個體化的,那麼 ABC t = new Class1() 究竟執行個體化了一個什麼東西?

 

1. 我是誰?

很久以前,成龍上演了一部《我是誰》,現在 t 也遭遇了相同的問題。成龍當時就不太幸運了,因為要喚醒人的記憶不是那麼容易;相比之下,t 就幸運的多了,因為它有中繼資料這張 ID 卡。那麼,t 究竟是誰?

//  Code #03

ABC t  =   new  Class1();
Console.WriteLine(t.GetType());

你猜答案是什嗎?是 Class1!

 

2. 選擇性透過...

既然 t 指向 Class1 的執行個體,為什麼 t.N() 不能通過編譯呢?如果你玩過 Flash,你會知道 Flash 的 Mask 可以做出類似於聚光燈的效果,把聚光圈以外的東西統統隱藏起來。從目標對象的角度來看,介面利用這種“遮掩”的特性“屏蔽”了目標對象的部分功能;從用戶端的角度來看,介面就像細胞膜那樣有選擇性的讓目標對象的功能進入用戶端的作用範圍。

請看:

對應 Code #01 和 Code #02,t 發揮了介面的“選擇性透過”特性,僅讓用戶端和 Class1 執行個體的 M() 接觸。

 

3. 噢,別這樣!

雖然 Code #02 中的 t 確實指向了 Class1 的執行個體,但編譯器卻不允許你調用 t.N(),因為 ABC 並不認識 Class1.N()。不過我們心知肚明 t 是有能力調用 N() 的,於是就去和編譯器溝通一下。最後我們和編譯器達成共識,讓 t 這樣調用 N():

//  Code #04

((Class1)t).N();

正當你為讓 t 發揮了潛能而高興時,你卻聽到另外一種聲音:別這樣!為什嗎?假如我們有這樣一個方法:

//  Code #05

void  Process(ABC abc)
{
    ((Class1)abc).N();
}

某天不知道誰搞了一個 Class2:

//  Code #06

class  Class2 : ABC
{
     public   void  M()
     {
        Console.WriteLine( " Now we are in Class1, using method which inherit from Interface ABC  " );
    }

     public   void  O()
     {
        Console.WriteLine( " Ouch! Are you expecting me? " );
    }
}

然後這個人把 Class2 的執行個體傳遞給 Process():

//  Code #07

ABC t  =   new  Class2();
Process(t);

那個人當然不知道我們在 Process 裡面搞什麼鬼,但卻莫名其妙的得到一個 InvalidCastException!

好吧,如果你需要在 Process 裡面處理 Class1 的執行個體,那你為什麼不直接把你的想法告訴別人呢?

//  Code #08

Process(Class1 c)
{
    c.N();
}

同樣的道理,如果我們希望調用 Class1.N(),為什麼我們不直接做:

//  Code #09

Class1 c  =   new  Class1();
c.N();

而要寫 Code #02 那樣的代碼呢?

回顧 Code #05,我們除了知道 abc 肯定有一個 M() 之外,根本無從得知具體的執行個體還會有別的什麼方法可用,那我們憑什麼要求 Code #02 可以通過編譯呢?

 

4. 我還應該說點什麼呢?

好吧,我們繞了一個大圈,最後發現雖然 ABC t = new Class1() 無法通過編譯,但 t 確實指向一個 Class1 執行個體,只是這個執行個體好像被 t 搞得有點“低能兒”罷了。我認為真正的問題並不在於 t 究竟是什麼,而是在於我們為什麼要這樣使用介面。這是一個很基礎的問題,除非你不打算在 OO 方面有所發展,否則你得把它弄清楚,要不然你真的會很麻煩,至少你會誤解介面的真正意義。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.