您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關如何繼承和擴展ObservableCollection,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
前段時間,我做的一個項目有一個小小的需求,即:對范型集合類型ObservableCollection< T>進行排序。ObservableCollection< >這個類型在WPF和Silverlight中非常有用,因為它實現了INotifyCollectionChanged接口,繼而在進行數據綁定的時候,如果將ItemsControl的ItemsSource屬性綁定到一個ObservableCollection< T>對象上,那么當這個集合變化的時候(Add, Remove, Insert, Clear等等),相應的ItemsControl也會同步Update。由于ObservableCollection< T>繼承自Collection< T>,因此它沒有List< T>提供的Sort方法,所以如果我們想對ObservableCollection進行排序的話,就需要自己實現。
繼承與擴展方法:兩個解決方案
針對這個需求,我想到兩個方案解決,方案一就是寫一個子類,繼承ObservableCollection,進而在其中實現Sort方法,相應的代碼如下:
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>添加擴展方法,相應的代碼如下:
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 }
注:以上的代碼只是例子,并沒有對Argument進行應有的check,也沒有考慮運行時是否會出現其他異常。
繼承與擴展方法之比較
這兩個方案都可以滿足需求,那么就需要對它們的進行一下比較以便采取更優秀的方案。結合以上的案例,我主要是以下幾點進行比較(當然也有一些并不適用于以上例子,我也一并比較了):
1)針對程序集引用與命名空間合并:
無論是繼承還是擴展方法,如果被繼承和擴展的類不在我們的程序集中,那么為了使用擴展的新功能,我們就必須引用這個新的程序集,同時我們可以在新的程序集中把命名空間寫成和原有類所在的命名空間一樣,因此在這一點上,二者是平手。
2)針對sealed類:
由于sealed類不能再被繼承,因此在這種情況下我們如果需要為某一個密封類擴展功能,那么只能考慮擴展方法,在這次較量中,擴展方法+1
3)針對public, protected, internal, private成員:
擴展方法其實只是語法糖,這點想必大家都清楚,因此在我們使用擴展方法的時候,是無法獲得對象private和protected成員的使用權限的,如果不在一個程序集中,internal也將變為不可見。相比之下,繼承的優勢在于可以訪問到protected成員,因此在此役中繼承+1
4)針對多態:
擴展方法只能對類擴展public成員,因此只能夠能過方法的overload來實現靜態多態特性,雖然通過this關鍵字傳入方法體的對象能夠在調用上使用override方法,但是您無永遠在擴展方法中實現override一個方法,而繼承則可以對基類中的abstract和virtual成員進行override,從而獲得動態多態特性,當然overload也成了小兒科。因此在此役中繼承+1
5)針對接口和抽象類的擴展方法:
C#3.0多出來的Linq命名空間下為IEnumerable接口添加了N多的擴展方法,雖然如果搞不清楚亂用會造成很多問題,但是它們的確讓我們的開發變得簡單明了。如果對于接口和抽象類實現擴展方法,那么受益者將會很多,凡是實現了該接口的類都將擁有這些擴展方法,而繼承(這里對于接口應該不能稱作繼承,而是implement)卻無法達到這一效果。當然有些功能我們只希望某一個類或者某一些類才有,而不是像擴展方法這樣讓所有抽象類的子類和實現接口的類都具有這個功能,但是在這次比較中,擴展方法仍然更勝一籌,擴展方法+1
6)針對代碼的擴展性和維護性:
有很多時候,代碼已經寫好才突然出現某一些附加的需求,比如我已經寫好了數據綁定的邏輯,用的正是ObservableCollection,如果我需要用繼承一個子類擴展Sort方法,那么我將需要更改很多處代碼。甚至有些時候代碼是別人寫的,已經編譯成程序集來給你用,你可以在他的代碼里得到ObservableCollection對象,卻再也無法將這個對象變成SortableObservableCollection使用了。因此在這種情況下,除非反編譯已經生成的程序集,不然就只能通過擴展方法實現了。而且如果再有新的需求,我們完全可以再寫一個static class加入新的擴展方法,這一點繼承一個子類是無法滿足需要的。因此,此役中擴展方法+1
7)關于反射:
大家都知道反射在某些時候是一種很方便的手段,或者說是不得不用的手段。在有反射參與的情況下,擴展方法可以說沒了用武之地,比如剛才那個ObservableCollection,我得到typeof(ObservableCollection)之后,仍然無法得到Sort方法的MethodInfo,因此也無法Invoke,原因是那個Sort方法是定義在ObservableCollectionExtension這個靜態類當中的,如果我想用Sort方法就必須反射ObservableCollectionExtension,這對于使用者是極為不便的。然后對于繼承,這個問題就不會出現,我當然能夠在SortableObservableCollection的Type中找到Sort方法對應的MethodInfo。因此,在有反射參與的情況下,繼承+1
8)關于面向對象:
我一直覺得面向對象是仁者見仁,智者見智的東西,而且不同的場合不同的應用對于兩個方案可能會有不同的選擇。按照道理說,無疑繼承更加面向對象一點,當然這只是我個人的感覺。其實上面提到過擴展方法也能夠在方法調用上體現多態,只不過是它無法override方法罷了。因此在這個比較上,繼承子類+0.5
通過上面的幾項比較,其實繼承和擴展方法兩者實在是難分伯仲。我覺得在選擇的時候還是要具體問題具體分析的,比如上面給出的有關protected和sealed這兩個問題,我們就是“不得不”做出選擇,而更多的情形還是需要考慮易用性以及代碼美觀等因素的。比如關于我那個項目,我最終選擇的擴展方法,原因就是我懶得去改以前的代碼了。
關于如何繼承和擴展ObservableCollection就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。