2010-05-18 48 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

相關問題