2010-05-18 50 views
1

我有一些看起来像下面的代码。首先,我有一些域类和一些特殊的比较器。如何让C#编译器自动推断出这些类型参数?

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类,这很好。

但是有一个问题。 C#编译器不能找出所涉及的类型,当你调用SemanticSequenceEquals:

// 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()); 

很显然,这是一个巨大的麻烦,这是不是很干。我可以在这里更改什么,以便我不必明确写入类型参数?

回答

2

尝试只是指定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)); 
} 
+0

为什么我没有想到这一点?这是最明显的解决方案,但我仍然必须明确指定“T”的类型参数。当它是两个方法参数的共享类型参数时,它看起来像编译器无法推断T. – 2010-05-18 01:48:28

1

您可以明确地将您的参数输入到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()); 
+0

确实。如果您不使用泛型,请不要使用泛型。你不需要U和V类型,所以你不应该包含它们。在这个例子中,SemanticSequenceEquals不需要知道它的参数实际上是列表,因为它只使用IEnumerable 功能。 – Joren 2010-05-18 01:44:49

+0

你说得对,'U'和'V'可以解决;我错过了这种各种明显的重构。不过,我似乎仍然需要明确指定'T'。您的示例(从SemanticSequenceEquals调用中省略了“T”规范)是否为您编译? – 2010-05-18 01:49:30

+0

它在VS2010中编译得很好,是的。不过我不得不添加一些'where T:class'说明符。 – 2010-05-18 02:06:04

相关问题