新聞中心
前段時(shí)間,我做的一個(gè)項(xiàng)目有一個(gè)小小的需求,即:對(duì)范型集合類型ObservableCollection< T>進(jìn)行排序。ObservableCollection< >這個(gè)類型在WPF和Silverlight中非常有用,因?yàn)樗鼘?shí)現(xiàn)了INotifyCollectionChanged接口,繼而在進(jìn)行數(shù)據(jù)綁定的時(shí)候,如果將ItemsControl的ItemsSource屬性綁定到一個(gè)ObservableCollection< T>對(duì)象上,那么當(dāng)這個(gè)集合變化的時(shí)候(Add, Remove, Insert, Clear等等),相應(yīng)的ItemsControl也會(huì)同步Update。由于ObservableCollection< T>繼承自Collection< T>,因此它沒有List< T>提供的Sort方法,所以如果我們想對(duì)ObservableCollection進(jìn)行排序的話,就需要自己實(shí)現(xiàn)。

扶余網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)公司從2013年創(chuàng)立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)公司。
繼承與擴(kuò)展方法:兩個(gè)解決方案
針對(duì)這個(gè)需求,我想到兩個(gè)方案解決,方案一就是寫一個(gè)子類,繼承ObservableCollection,進(jìn)而在其中實(shí)現(xiàn)Sort方法,相應(yīng)的代碼如下:
1 public class SortableObservableCollection< T> : ObservableCollection< T>
2 {
3 public void Sort()
4 {
5 Sort(Comparer< T>.Default);
6 }
7
8 public void Sort(IComparer< T> comparer)
9 {
10 int i, j;
11 T index;
12 for (i = 1; i < this.Count; i++)
13 {
14 index = Items[i];
15 j = i;
16 while ((j > 0) && (comparer.Compare(Items[j - 1], index) == 1))
17 {
18 Items[j] = Items[j - 1];
19 j = j - 1;
20 }
21 Items[j] = index;
22 }
23 }
24 }方案二是為ObservableCollection< T>添加擴(kuò)展方法,相應(yīng)的代碼如下:
1 public static class ObservableCollectionExtension
2 {
3 public static void Sort< T>(this ObservableCollection< T> Collection)
4 {
5 Collection.Sort(Comparer< T>.Default);
6 }
7
8 public static void Sort< T>(this ObservableCollection< T> Collection, IComparer< T> comparer)
9 {
10 int i, j;
11 T index;
12 for (i = 1; i < Collection.Count; i++)
13 {
14 index = Collection[i];
15 j = i;
16 while ((j > 0) && (comparer.Compare(Collection[j - 1], index) == 1))
17 {
18 Collection[j] = Collection[j - 1];
19 j = j - 1;
20 }
21 Collection[j] = index;
22 }
23 }
24 }注:以上的代碼只是例子,并沒有對(duì)Argument進(jìn)行應(yīng)有的check,也沒有考慮運(yùn)行時(shí)是否會(huì)出現(xiàn)其他異常。
繼承與擴(kuò)展方法之比較
這兩個(gè)方案都可以滿足需求,那么就需要對(duì)它們的進(jìn)行一下比較以便采取更優(yōu)秀的方案。結(jié)合以上的案例,我主要是以下幾點(diǎn)進(jìn)行比較(當(dāng)然也有一些并不適用于以上例子,我也一并比較了):
1)針對(duì)程序集引用與命名空間合并:
無論是繼承還是擴(kuò)展方法,如果被繼承和擴(kuò)展的類不在我們的程序集中,那么為了使用擴(kuò)展的新功能,我們就必須引用這個(gè)新的程序集,同時(shí)我們可以在新的程序集中把命名空間寫成和原有類所在的命名空間一樣,因此在這一點(diǎn)上,二者是平手。
2)針對(duì)sealed類:
由于sealed類不能再被繼承,因此在這種情況下我們?nèi)绻枰獮槟骋粋€(gè)密封類擴(kuò)展功能,那么只能考慮擴(kuò)展方法,在這次較量中,擴(kuò)展方法+1
3)針對(duì)public, protected, internal, private成員:
擴(kuò)展方法其實(shí)只是語法糖,這點(diǎn)想必大家都清楚,因此在我們使用擴(kuò)展方法的時(shí)候,是無法獲得對(duì)象private和protected成員的使用權(quán)限的,如果不在一個(gè)程序集中,internal也將變?yōu)椴豢梢?。相比之下,繼承的優(yōu)勢(shì)在于可以訪問到protected成員,因此在此役中繼承+1
4)針對(duì)多態(tài):
擴(kuò)展方法只能對(duì)類擴(kuò)展public成員,因此只能夠能過方法的overload來實(shí)現(xiàn)靜態(tài)多態(tài)特性,雖然通過this關(guān)鍵字傳入方法體的對(duì)象能夠在調(diào)用上使用override方法,但是您無永遠(yuǎn)在擴(kuò)展方法中實(shí)現(xiàn)override一個(gè)方法,而繼承則可以對(duì)基類中的abstract和virtual成員進(jìn)行override,從而獲得動(dòng)態(tài)多態(tài)特性,當(dāng)然overload也成了小兒科。因此在此役中繼承+1
5)針對(duì)接口和抽象類的擴(kuò)展方法:
C#3.0多出來的Linq命名空間下為IEnumerable接口添加了N多的擴(kuò)展方法,雖然如果搞不清楚亂用會(huì)造成很多問題,但是它們的確讓我們的開發(fā)變得簡(jiǎn)單明了。如果對(duì)于接口和抽象類實(shí)現(xiàn)擴(kuò)展方法,那么受益者將會(huì)很多,凡是實(shí)現(xiàn)了該接口的類都將擁有這些擴(kuò)展方法,而繼承(這里對(duì)于接口應(yīng)該不能稱作繼承,而是implement)卻無法達(dá)到這一效果。當(dāng)然有些功能我們只希望某一個(gè)類或者某一些類才有,而不是像擴(kuò)展方法這樣讓所有抽象類的子類和實(shí)現(xiàn)接口的類都具有這個(gè)功能,但是在這次比較中,擴(kuò)展方法仍然更勝一籌,擴(kuò)展方法+1
6)針對(duì)代碼的擴(kuò)展性和維護(hù)性:
有很多時(shí)候,代碼已經(jīng)寫好才突然出現(xiàn)某一些附加的需求,比如我已經(jīng)寫好了數(shù)據(jù)綁定的邏輯,用的正是ObservableCollection,如果我需要用繼承一個(gè)子類擴(kuò)展Sort方法,那么我將需要更改很多處代碼。甚至有些時(shí)候代碼是別人寫的,已經(jīng)編譯成程序集來給你用,你可以在他的代碼里得到ObservableCollection對(duì)象,卻再也無法將這個(gè)對(duì)象變成SortableObservableCollection使用了。因此在這種情況下,除非反編譯已經(jīng)生成的程序集,不然就只能通過擴(kuò)展方法實(shí)現(xiàn)了。而且如果再有新的需求,我們完全可以再寫一個(gè)static class加入新的擴(kuò)展方法,這一點(diǎn)繼承一個(gè)子類是無法滿足需要的。因此,此役中擴(kuò)展方法+1
7)關(guān)于反射:
大家都知道反射在某些時(shí)候是一種很方便的手段,或者說是不得不用的手段。在有反射參與的情況下,擴(kuò)展方法可以說沒了用武之地,比如剛才那個(gè)ObservableCollection,我得到typeof(ObservableCollection)之后,仍然無法得到Sort方法的MethodInfo,因此也無法Invoke,原因是那個(gè)Sort方法是定義在ObservableCollectionExtension這個(gè)靜態(tài)類當(dāng)中的,如果我想用Sort方法就必須反射ObservableCollectionExtension,這對(duì)于使用者是極為不便的。然后對(duì)于繼承,這個(gè)問題就不會(huì)出現(xiàn),我當(dāng)然能夠在SortableObservableCollection的Type中找到Sort方法對(duì)應(yīng)的MethodInfo。因此,在有反射參與的情況下,繼承+1
8)關(guān)于面向?qū)ο螅?/p>
我一直覺得面向?qū)ο笫侨收咭娙?,智者見智的東西,而且不同的場(chǎng)合不同的應(yīng)用對(duì)于兩個(gè)方案可能會(huì)有不同的選擇。按照道理說,無疑繼承更加面向?qū)ο笠稽c(diǎn),當(dāng)然這只是我個(gè)人的感覺。其實(shí)上面提到過擴(kuò)展方法也能夠在方法調(diào)用上體現(xiàn)多態(tài),只不過是它無法override方法罷了。因此在這個(gè)比較上,繼承子類+0.5
通過上面的幾項(xiàng)比較,其實(shí)繼承和擴(kuò)展方法兩者實(shí)在是難分伯仲。我覺得在選擇的時(shí)候還是要具體問題具體分析的,比如上面給出的有關(guān)protected和sealed這兩個(gè)問題,我們就是“不得不”做出選擇,而更多的情形還是需要考慮易用性以及代碼美觀等因素的。比如關(guān)于我那個(gè)項(xiàng)目,我最終選擇的擴(kuò)展方法,原因就是我懶得去改以前的代碼了。
那么對(duì)于繼承與擴(kuò)展方法這兩種方式對(duì)于擴(kuò)展一個(gè)類的的比較就到此為止了,歡迎大家進(jìn)行補(bǔ)充,并指出我的不足之處。
本文來自wodehuajianrui的博客。
當(dāng)前名稱:有關(guān)繼承與擴(kuò)展方法之比較:ObservableCollection
URL網(wǎng)址:http://m.fisionsoft.com.cn/article/coscghd.html


咨詢
建站咨詢
