在编程中,经常需要对集合进行去重操作。LINQ提供了一个非常便捷的Distinct
方法来实现这一功能。但是,LINQ的Distinct
方法默认使用对象的Equals
和GetHashCode
方法来确定元素的唯一性。在某些情况下,需要根据自定义的条件来确定两个对象是否相等。这时,就需要编写自定义的比较器。
在C#中,可以通过实现IEqualityComparer
接口来创建自定义比较器。但是,如果需要为多个不同的类型或条件创建比较器,每次都编写一个新的比较器可能会变得繁琐。因此,决定创建一个泛型比较器,它接受一个自定义的谓词函数作为参数。
以下是泛型比较器的一个简单实现:
public class PredicateEqualityComparer : EqualityComparer
{
private Func predicate;
public PredicateEqualityComparer(Func predicate)
: base()
{
this.predicate = predicate;
}
public override bool Equals(T x, T y)
{
if (x != null)
{
return (y != null) && this.predicate(x, y);
}
if (y != null)
{
return false;
}
return true;
}
public override int GetHashCode(T obj)
{
// Always return the same value to force the call to IEqualityComparer.Equals
return 0;
}
}
使用这个泛型比较器,可以这样写代码:
.Distinct(new PredicateEqualityComparer- ((x, y) => x.Field == y.Field))
但是,很快意识到这样的代码失去了LINQ的简洁性和表达力,并且它不支持匿名类型。因此,创建了一个Distinct
的扩展方法,允许直接传入一个谓词函数。
以下是扩展方法的实现:
public static IEnumerable Distinct(
this IEnumerable source, Func predicate)
{
return source.Distinct(new PredicateEqualityComparer(predicate));
}
现在,可以这样写查询:
.Distinct((x, y) => x.Field == y.Field)
这样看起来好多了,不是吗?而且它支持匿名类型。
更新:不小心发布了错误的IEqualityComparer
方法版本。
通过这种方式,可以灵活地为LINQ的Distinct
方法提供自定义的比较逻辑,无论是对于简单类型还是复杂的对象,都可以轻松实现去重操作。
在实际开发中,可能会遇到各种需要自定义比较逻辑的场景。例如,可能需要比较两个对象的特定字段,或者需要忽略某些字段的差异。通过泛型比较器,可以轻松地实现这些需求,而不需要为每种情况编写单独的比较器。