您的位置:首页 > 其它

快速创建 IEqualityComparer<T> 和 IComparer<T> 的实例

2012-03-19 09:49 549 查看

快速创建 IEqualityComparer<T> 和 IComparer<T> 的实例

2011-08-02 21:14 by 鹤冲天, 1935 visits,
收藏,
编辑

几篇相关文章:《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> 类能满足多数需求。

如果本文对你有帮助,请推荐本文,让更多的朋友受益。

-------------------

思想火花,照亮世界
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: