我有一些代码如下所示。首先,我有一些域类和一些特殊的比较器。
public class Fruit {
public int Calories { get; set; }
public string Name { get; set; }
}
public class FruitEqualityComparer : IEqualityComparer<Fruit> {
// ...
}
// A basket is just a group of Fruits.
public class BasketEqualityComparer : IEqualityComparer<IEnumerable<Fruit>> {
// ...
}
接下来,我有一个名为
ConstraintChecker
的辅助类。它有一个简单的 BaseEquals
方法,确保考虑一些简单的基本情况:
public static class ConstraintChecker {
public static bool BaseEquals(T lhs, T rhs) {
bool sameObject = l == r;
bool leftNull = l == null;
bool rightNull = r == null;
return sameObject && !leftNull && !rightNull;
}
还有一个
SemanticEquals
方法,它只是一个 BaseEquals
检查和您指定的比较器函数。
public static bool SemanticEquals<T>(
T lhs, T rhs, Func<T, T, bool> f) {
return BaseEquals(lhs, rhs) && f(lhs, rhs);
}
最后有一个
SemanticSequenceEquals
方法,它接受两个 IEnumerable<T>
实例进行比较,以及一个 IEqualityComparer 实例,该实例将通过 Enumerable.SequenceEquals
在列表中的每对元素上调用。
public static bool SemanticSequenceEquals<T, U, V>(U lhs,
U rhs,
V comparator)
where U : IEnumerable<T>
where V : IEqualityComparer<T> {
return SemanticEquals(lhs, rhs, (l, r) => lhs.SequenceEqual(rhs, comparator));
}
} // end of ConstraintChecker
SemanticSequenceEquals
的要点是,每当您想要比较 IEnumerable<T>
和 T
实例时,都不必定义两个比较器;现在您只需指定一个 IEqualityComparer<T>
,当您调用 SemanticSequenceEquals
时它也会处理列表。所以我可以摆脱 BasketEqualityComparer 类,这会很好。
但是有一个问题。当您调用 SemanticSequenceEquals 时,C# 编译器无法确定涉及的类型:
// Error! Compiler can't infer the type parameters.
return ConstraintChecker.SemanticSequenceEquals(lhs, rhs,
new FruitEqualityComparer());
如果我明确指定它们,它就会起作用:
return ConstraintChecker.SemanticSequenceEquals<Fruit, IEnumerable<Fruit>,
IEqualityComparer<Fruit>> (lhs, rhs, new FruitEqualityComparer());
显然,这是一个巨大的麻烦,而且不是很DRY。我可以在这里更改什么,以便不必显式编写类型参数?
尝试仅指定 T,而不像这样指定 U 和 V。
public static bool SemanticSequenceEquals<T>(
IEnumerable<T> lhs,
IEnumerable<T> rhs,
IEqualityComparer<T> comparator)
{
return SemanticEquals(lhs, rhs, (l, r) => lhs.SequenceEqual(rhs, comparator));
}
您可以将参数显式键入 SemanticSequenceEquals。 这对我来说似乎编译得很好:
public static bool SemanticSequenceEquals<T>(IEnumerable<T> lhs, IEnumerable<T> rhs, IEqualityComparer<T> comparator)
{
return SemanticEquals(lhs, rhs, (l, r) => lhs.SequenceEqual(rhs, comparator));
}
List<Fruit> a, b;
return ConstraintChecker.SemanticSequenceEquals(a, b, new FruitEqualityComparer());