C#中實現(xiàn)多繼承的方法
近日看到了一個貼子,就是在C#語言中,如何實現(xiàn)多繼承的問題。相信涉獵c#不多的人(像我這樣的菜鳥),一看就覺得很可笑,c#肯定是不能實現(xiàn)多繼承的啊。都知道在c++中因為實現(xiàn)多繼承會有很多的歧義問題,所以在c#中就把多繼承給取消了,而用接口來實現(xiàn)!但是想想,如果是初學者肯定不會不會問這樣的問題。肯定是個高手,然后就開始上網(wǎng)查資料!然后發(fā)現(xiàn)真的可以實現(xiàn)!
說起多繼承,首先大家可以想想這個問題:你知道在C#中怎么實現(xiàn)多繼承嗎?
主流的答案無非2種。
答案一:用接口啊,一個類可以繼承自多個接口的。
答案二:C#不支持多繼承,C++才支持多繼承,多繼承會讓代碼變得很亂,因此微軟在設計C#的時候放棄了多繼承。
能夠知道答案二的人顯然懂的更多,我也在很長一段時間內(nèi)相信C#不支持多繼承,直到2013年5月的一個項目中,我偶然的發(fā)現(xiàn)自己的代碼就完全實現(xiàn)了真正意義的多繼承。
先說說什么是真正意義的多繼承。真正的多繼承應該是像C++那樣的,而不是說像在C#里面一個類繼承了多個接口就叫多繼承。在C#中,如果一個類實現(xiàn)了多個接口,那么要為每個接口寫實現(xiàn),如果接口被多個類繼承,那么就會有重復的代碼,這顯然是無法接受的。
然而C++那樣的多繼承也確確實實給編碼帶來了很大的麻煩,我也相信微軟真的是因為意識到了多繼承的不合理之處才在C#中擯棄了這個特性。而我在C#中實現(xiàn)的多繼承,第一是真正的多繼承,第二代碼寫的很合理。
請看案例
假如你有一個類叫老虎,還有一個類叫蒼蠅?,F(xiàn)在你想新創(chuàng)一個超級老虎類,一種可以飛的老虎。在C++中,你可以定義一種超級老虎類,讓其繼承自老虎和蒼蠅,這樣這種老虎就可以飛了。然而,問題出現(xiàn)了,這種超級老虎由于同時也繼承自蒼蠅,而蒼蠅下面有個方法叫吃,參數(shù)類型是屎。吃屎的這個方法顯然跟我們的超級老虎太不搭了。
雖然這個例子有些夸張,但是很多C++程序員真的就是這樣在設計代碼。由于子類繼承了多個父類,而多個父類肯定有些成員跟這個子類不搭調(diào),于是子類的調(diào)用者就很難受了。比如上面這個例子,當調(diào)用者拿到超級老虎的一個實例時,發(fā)現(xiàn)超級老虎下面怎么會有個吃屎的方法呢!??!真的是要笑死人了。
C++要這樣允許多繼承就必然會造成這個問題。C#程序員就絕對不會寫出這樣滑稽的代碼。對于C#程序員,肯定是要把這個飛的方法提成接口的,然后讓蒼蠅類和超級老虎類都繼承自這個接口。這樣,蒼蠅會飛,超級老虎也會飛。是不是完美解決這個問題?
問題看上去解決了,但是,假如我跟你說蒼蠅飛的方法跟超級老虎飛的方法需要一模一樣:首先張開雙翅,身體前傾,拍打雙翅,起飛,繼續(xù)拍打。我們肯定不能把同一份代碼copy一份吧,那是屬于入門級程序員干的事,我們現(xiàn)在已經(jīng)沒資格干那事了。那怎么辦呢?簡單快速的做法是使用靜態(tài)方法,比如FlyHelper.Fly(...)。
靜態(tài)方法解決了代碼重用的問題,但寫起來始終覺得哪里不對勁。我的超級老虎類和蒼蠅都明明繼承了飛了啊,為什么還要這樣調(diào)用一句靜態(tài)方法。如果以后哪天我想讓我的豬也能飛起來,那豈不是還要來調(diào)用這個靜態(tài)方法。
到底怎樣才能在C#中實現(xiàn)像C++那樣優(yōu)雅的繼承呢?
答案揭曉
答案其實很簡單,那就是給IFly接口寫擴展方法。
首先請看這個空接口的定義,及其擴展方法(注意泛型限制):
namespace Interface
{
//飛的接口
public interface IFly
{
}
//擴展方法
public static class ExtendFly
{
public static void StartFly<T>(this T example) where T : IFly
{
Console.WriteLine("準備");
Console.WriteLine("張開雙翅");
Console.WriteLine("起飛");
Console.WriteLine("我飛,我飛,我飛飛飛");
}
}
}
再看老虎和蒼蠅的實現(xiàn):
namespace Interface
{
//蒼蠅類實現(xiàn)飛的接口
public class flies : IFly
{
public void fly()
{
//調(diào)用接口中飛的方法
this.StartFly();
}
}
}
namespace Interface
{
//老虎類
public class Tiger
{
public void introduce()
{
Console.WriteLine("I am a tiger");
}
}
}
再看超級老虎的實現(xiàn):
namespace Interface
{
//超級老虎類,繼承了老虎類,并實現(xiàn)了飛的方法
public class SuperTiger : Tiger, IFly
{
public override void introduce()
{
Console.WriteLine("大家好,我是超級老虎哦!");
}
public void TigerFly()
{
//調(diào)用接口中飛的方法
this.StartFly();
}
}
}
怎么樣,你看明白了嗎?這個實現(xiàn)是不是很簡單呢?好處是不是大大的有呢?
當以后哪天老板讓你實現(xiàn)一個會飛的超級豬的話,你只需要讓你的超級豬繼承“I飛”接口就行了。當哪天老板又不想要這個超級豬飛的話,你也只需要將這個接口繼承刪掉而已。如果你正在開發(fā)一個動物王國程序,你可以將飛的功能注入到任何一種動物身上。想想是不是都覺得很爽。
總結
最后,再讓我們回顧一下之前用C++寫的超級老虎吃屎的變態(tài)例子。這實際上不是C++的錯,而是程序員用錯了多繼承。雖然在語法上C++沒有限制程序員怎么去寫多繼承,但是從上面的例子分析來看,我們很容得出這樣一個結論:
當需要寫多繼承的時候,被繼承的父類只能是一個功能,而不應是一個完整的類。
如果按照這個思路,那么今天的這個例子在C++中就可以這樣寫,首先提一個Flyable的類出來,然后讓超級老虎和蒼蠅都繼承這個Flyable。
在C#中,雖然實現(xiàn)多繼承的代碼稍微繞了個彎,但是多繼承帶來的好處是非常明顯的:對不同的類實現(xiàn)注入式的功能,讓你的代碼更符合面向?qū)ο蟮乃枷搿?/p>
相關文章
C#中datagridview使用tooltip控件顯示單元格內(nèi)容的方法
這篇文章主要介紹了C#中datagridview使用tooltip控件顯示單元格內(nèi)容的方法,實例分析了C#控件的相關使用技巧,需要的朋友可以參考下2016-06-06c# 網(wǎng)址壓縮簡單實現(xiàn)短網(wǎng)址
短網(wǎng)址,忽然一下子就冒出來的東西,長長的一個URL,提交過去,出來就只有短短的一個URL了,看起來似乎挺神奇,其實簡單分析一下,明白其中的原理,也是一件很簡單的事情,需要的朋友可以了解下2012-12-12