快速创建 IEqualityComparer<T> 和 IComparer<T> 的实例
2011-08-02 21:14 鹤冲天 阅读(11605) 评论(16) 编辑 收藏 举报几篇相关文章:《Linq的Distinct太不给力了》、《c# 扩展方法奇思妙用基础篇八:Distinct 扩展》、《何止 Linq 的 Distinct 不给力》,建议先看下。
.net 中 IEqualityComparer<T> 和 IComparer<T> 经常在 Linq 和 一些泛型集合、泛型字典类中用作参数。不过因其复杂性,包含 IEqualityComparer<T> 或 IComparer<T> 类型参数的函数一般使用频度不高。
尽管如此,有些情况下确非用不可,不得不创建一些新的类来实现 IEqualityComparer<T> 或 IComparer<T> 接口。不但增加了代码量,还对程序结构产生影响,新加入的类命名、放置、共用都是问题。
因此,我们期望能简单快速直接的创建 IEqualityComparer<T> 和 IComparer<T> 的实例。
本文给出两个实用类来实现这个目标,实现原理日后另撰文详述。
快速创建 IEqualityComparer<T> 的实例
我前一篇文章 《何止 Linq 的 Distinct 不给力》讨论的就是这个话题,这里就不再重复了,直接将 《何止 Distinct 不给力》一文中的总结出的实用类给出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public static class Equality<T> { public static IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector) { return new CommonEqualityComparer<V>(keySelector); } public static IEqualityComparer<T> CreateComparer<V>(Func<T, V> keySelector, IEqualityComparer<V> comparer) { return new CommonEqualityComparer<V>(keySelector, comparer); } class CommonEqualityComparer<V> : IEqualityComparer<T> { private Func<T, V> keySelector; private IEqualityComparer<V> comparer; public CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer) { this.keySelector = keySelector; this.comparer = comparer; } public CommonEqualityComparer(Func<T, V> keySelector) : this(keySelector, EqualityComparer<V>.Default) { } public bool Equals(T x, T y) { return comparer.Equals(keySelector(x), keySelector(y)); } public int GetHashCode(T obj) { return comparer.GetHashCode(keySelector(obj)); } } } |
Equality<T> 代码比较简洁,其中的关键是 EqualityComparer<V> 类和它的 Default 属性(有时间专门写篇文章来讲解)。
使用示例:
1 2 3 4 |
var equalityComparer1 = Equality<Person>.CreateComparer(p => p.ID); var equalityComparer2 = Equality<Person>.CreateComparer(p => p.Name); var equalityComparer3 = Equality<Person>.CreateComparer(p => p.Birthday.Year); var equalityComparer4 = Equality<Person>.CreateComparer(p => p.Name, StringComparer.CurrentCultureIgnoreCase); |
Person 是一个简单的实体类:
1 2 3 4 5 6 |
class Person { public int ID { get; set; } public string Name { get; set; } public DateTime Birthday { get; set; } } |
快速创建 IComparer<T> 的实例
参照上面的代码,照猫画虎,很容易写出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public static class Comparison<T> { public static IComparer<T> CreateComparer<V>(Func<T, V> keySelector) { return new CommonComparer<V>(keySelector); } public static IComparer<T> CreateComparer<V>(Func<T, V> keySelector, IComparer<V> comparer) { return new CommonComparer<V>(keySelector, comparer); } class CommonComparer<V> : IComparer<T> { private Func<T, V> keySelector; private IComparer<V> comparer; public CommonComparer(Func<T, V> keySelector, IComparer<V> comparer) { this.keySelector = keySelector; this.comparer = comparer; } public CommonComparer(Func<T, V> keySelector) : this(keySelector, Comparer<V>.Default) { } public int Compare(T x, T y) { return comparer.Compare(keySelector(x), keySelector(y)); } } } |
后注:这个类的名字起得不好,和 System.Comparison<T> 重名了,使用时最好改成其它名称如:ComparisonHelper<T>。
类似,Comparison<T> 的关键是 Comparer<V> 类和它的 Default 属性。
使用也是极其相似:
1 2 3 3 |
var comparer1 = Comparison<Person>.CreateComparer(p => p.ID); var comparer2 = Comparison<Person>.CreateComparer(p => p.Name); var comparer3 = Comparison<Person>.CreateComparer(p => p.Birthday.Year); var comparer4 = Comparison<Person>.CreateComparer(p => p.Name, StringComparer.CurrentCultureIgnoreCase); |
总结
借助本文中的 Equality<T> 和 Comparison<T>,可以不必引入新的类、不必自己实现接口,也减少了编码和维护的工作量。
预计 Equality<T> 和 Comparison<T> 类能满足多数需求。
如果本文对你有帮助,请推荐本文,让更多的朋友受益。
-------------------
思想火花,照亮世界