.NET 4.0中數組的新增功能
1、兩數組是否“相等”?
在實際開發中,有時我們需要比對兩個數組是否擁有一致的元素,例如,以下兩個數組由于擁有相同的元素,因此被認為是相等的:
{
1,2,3,4
};
int[] arr2 = new int[]
{
1,2,3,4
};
在.NET早期版本中,要實現上述數組比對功能,必須自己動手編寫一個函數,在其內部使用循環語句逐個比較兩個數組的對應元素,才知道這兩個數組是否相等。
在.NET 4.0中,數組基類Array實現了一個新增的接口IStructuralEquatable,從而使得所有數組都可直接比對其所擁有的元素是否相等。
IStructuralEquatable接口的定義如下,其中最重要的成員就是它所定義的Equals()方法。
{
bool Equals(object other, IEqualityComparer comparer);
int GetHashCode(IEqualityComparer comparer);
}
上述聲明中還涉及另一個接口IEqualityComparer,它的聲明如下:
{
bool Equals(object x, object y);
int GetHashCode(object obj);
}
實現了IEqualityComparer接口的對象被稱為“集合對象相等比較器”。
.NET 4.0基類庫中提供了好幾個直接可用的“集合對象相等比較器”,有兩種方式獲取這些預定義的“集合對象相等比較器”:
(1)使用StructuralComparisons類的靜態屬性StructuralEqualityComparer獲取一個StructuralEqualityComparer類型實例的引用。
延伸閱讀:
“程序集接口最小化”設計原則
StructuralComparisons和StructuralEqualityComparer這兩個類型均屬于System.Collections命名空間,位于.NET的核心程序集mscorlib.dll內,前者是public的,而后者是internal的。
默認情況下,聲明為internal的類型只能在本程序集內使用,其它程序集無法“看到”它。
因此,StructuralComparisons類在定義其靜態屬性StructuralEqualityComparer時,沒有直接向外界暴露StructuralEqualityComparer類型,而是將其轉換為公有的IEqualityComparer接口:
{
public static IEqualityComparer StructuralEqualityComparer { get; }
//……
}
這種設計方法貫徹了.NET組件化開發中的“程序集接口最小化”原則。該原則說:設計一個程序集時應該盡可能地減少聲明為public的類型。
.NET設計者在設計public類型StructuralComparisons時,沒有讓其靜態屬性直接將一個StructuralEqualityComparer對象的引用返回給外界,而將其轉換為一個外界“知道”的公有接口IEqualityComparer,從而將StructuralEqualityComparer類型的定義完全封裝在程序集內部,外界甚至不知道有這么一個類型的存在。
這種設計方式的好處是:
我們可以在程序集內部設計任意多個實現了IEqualityComparer接口的類型,由于這些類型對于外界而言是“透明”的,因此,程序集內部的修改對外界程序集使用者可能帶來的影響就很小了。
這種設計方法值得注意。
(2)使用EqualityComparer靜態屬性Default獲取一個.NET4.0針對泛型類型T所提供的默認“集合對象相等比較器”對象的引用,同樣地,它沒有將程序集內部的某個具體類型發布出去,而是玩了一點小花樣,發布了一個實現了IEqualityComparer接口的公有抽象基類EqualityComparer:
IEqualityComparer, IEqualityComparer
{
public static EqualityComparer Default { get; }
//...
}
可以將.NET基類庫設計者的設計思路表述為下圖 。
因此,使用上述兩種方式的任意一種,我們可以寫出以下代碼來直接判斷兩個整型數組是否擁有完全一致元素:
arr2, StructuralComparisons.StructuralEqualityComparer);
bool IsEqual2=(arr1 as IStructuralEquatable).Equals(
arr2, EqualityComparer.Default)
當比對兩個數組時,如果兩個數組的長度不一樣,數組基類Array所實現的IStructuralEquatable.Equals()方法將返回false,否則,它逐個比較兩個數組的對應元素,找到一個不同的,返回false,如果一直比較完所有元素,都沒有發現有不同的,則Equals()方法返回true。
2、兩個數組“誰大誰小”?
如果兩個數組的長度一樣,我們還可以定義這兩個數組“誰大誰小”:
{
1,2,3,4
};
int[] arr2 = new int[]
{
1,2,3,5
};
上述兩個數組中,由于arr1與arr2前幾個元素都相等,但第4個元素arr2大于arr1,所以,我們認為:arr2“大于”arr1
為了比較兩個集合的大小,.NET 4.0引入了一個新的接口IStructuralComparable,并且讓數組基類Array也實現了此接口,這意味著在.NET 4.0中,兩個數組對象是可以比較“大小”的。
{
int CompareTo(object other, IComparer comparer);
}
注意上面的接口聲明中用到了一個實現IComparer接口的“集合對象大小比較器”對象。.NET基類庫同樣提供了幾個默認的“集合對象大小比較器”可供直接使用,也有兩種方式獲取這些默認的“集合對象大小比較器”實例:
(1)通過我們前面用過的StructuralComparisons類的另一個靜態屬性StructuralComparer獲取,它在內部使用System.Collections.Comparer類的Default靜態屬性所引用的包容了本地文化信息(CultureInfo)的Comparer對象來完成比較大小的工作,此對象是CLR在裝入程序集時創建的。
(2)通過Comparer.Default屬性獲取針對特定類型的默認“集合對象大小比較器”對象。
由此,我們可以寫出以下代碼來比較兩個整型數組誰大誰小:
arr2, StructuralComparisons.StructuralComparer);
int result2= (arr1 as IStructuralComparable).CompareTo(
arr2,Comparer.Default)
如果arr1>arr2,我們得到“1”;arr1,我們得到“-1”;arr1“等于”arr2,我們得到“0”。
3、小結
由于.NET 4.0讓數組基類Array實現了IStructuralEquatable和IStructuralComparable兩個接口,從而使得所有數組都可以直接比較其內容了。
通常情況下,使用.NET 4.0提供的幾個預定義集合對象比較器就足夠了,不過,我們也可以通過定義自己的“集合對象相等比較器”(只需定義一個實現IEqualityComparer 接口的類)或“集合對象大小比較器”(只需定義一個實現IComparer接口的類),從而定義自己的數組比較規則。
對于其元素為自定義引用類型的數組,推薦讓此自定義類型實現IComparable接口,并且重寫Object.Equals()方法。這么做的目的是讓數組中的所有對象都可以相互比較,并且能直接調用數組基類Array所提供的排序、查找、篩選等功能。
另外,.NET基類庫中相關的設計方案也是值得大家學習借鑒的。
我在本文中詳細介紹了.NET基類庫如何設計集合對象相等比較器,但沒有介紹它是如何設計集合對象大小比較器的,這個進一步深入探索的任務就留給好奇心強的讀者,我只想指出一點,.NET 基類庫中,集合對象大小比較器與集合對象相等比較器的設計思路是類似的。
留言列表