2016-01-06 84 views
3

我有一個樹型的類Foo<T>與它的接口IFoo<T>我有一個類A <T>:IEnumerable <T>,我想添加IEquatable <A<T>>如果T:IEquatable <T>。我該怎麼做,並保持IEnumerable呢?

我想Foo<T>能夠實現IEquatable<Foo<T>>T : IEquatable<T>(或者更一般地,如果T : I<T>我可能會在另外的其他實現的接口要Foo<T> : I<Foo<T>>)。

我試圖僞下面的代碼:

public interface IFoo<T> : IEnumerable<IFoo<T>> 
... 


public class Foo<T> : IFoo<T> 
... 


public interface IFooTwo<T> : IFoo<T>, IEquatable<IFooTwo<T>> 
    where T : IEquatable<T> 
... 

public class FooTwo<T> : IFooTwo<T> { 
... // I implement Equals 
    public bool NewMethod(FooTwo<T> Other) { ... } 
}  

所以,現在我已成功實施Equals(我也overrided的geniric平等相待,等等)。

FooTwo<T>現在不執行IEnumerable<IFooTwo<T>>(而是它實現IEnumerable<IFoo<T>>)。

所以我有兩個問題:

  1. 有沒有更好的辦法,我來組織我的代碼以實現我的目標(如果T : IEquatable<T>我希望能夠實現IEquatable<Foo<T>>Foo<T>)?一種有條件的where
  2. 如何使用 Foo<T> IEnumerable快速輕鬆地實現FooTwo<T> implements IEnumerable <FooTwo<T>>

編輯:

IEquatable<Foo<T>>的特殊情況下,我有疑問1.一個簡單的答案我可以測試是否T:IEquatable<T>並根據需要更改我的執行IEquatable<Foo<T>>。不過,我仍然想知道如何在更一般的情況下做到這一點。

+2

你如何重新實現'IEnumerable >'而不是'IEnumerable >'? –

+0

你是對的,編輯 –

+0

**請**注意編輯問題時的預覽窗格,尤其是當您試圖討論泛型類型參數時。我已經修復了一次你的代碼,我沒有心情再次爲你的修改做這件事(請嘗試閱讀,因爲它目前顯示,並看看它有多少意義) –

回答

1

因爲你實質上是在試圖讓一些IFoo<T>對象是IEquatable<T>而有些不是,這顯然與類型系統不一致,所以我完全避免IEquatable<T>。使用IEqualityComparer<T>。只需提供一種方法,在給定IEqualityComparer<T>(或使用默認比較器T,如果需要)時創建IEqualityComparer<IFoo<T>>

通過這樣做,任何IFoo<T>對象都有義務進行比較,但只要知道如何比較基礎對象,任何人都可以創建共同對象的方法。

這也完全不需要多個實現IFoo<T>,大大簡化了整個代碼庫,並完全消除了其他問題。

我怎樣才能讓FooTwo<T>器具IEnumerable<FooTwo<T>>使用一個快速簡便的方法 Foo<T> IEnumerable實施?

(如果您選擇不跟隨我的建議改變你如何處理平等:)

如果你知道所有的序列中的項目是在正確的類型其實,你可以簡單地使用Cast<FooTwo<T>>()

如果序列中的項目實際上不是FooTwo<T>對象,那麼您需要將項目投影到一個新的序列中,在此將每個IFoo<T>項目映射到FooTwo<T>項目。

2

對於問題1,你應該考慮你是否真的需要這個。 IEquatable<T>mostly exists for performance reasons relating to value types。在你的情況下,不應該有任何理由,你需要確保你使用的是平等而不是目標。例如,這是Tuple<T>所做的。那麼你可以只有一個沒有約束的接口:

public interface IFoo<T> : IEnumerable<IFoo<T>>, IEquatable<IFoo<T>> 

對於問題2,你可能不需要這個。 IEnumerable<T>covariant,這意味着如果您有IEnumerable<A>,則只要A可以分配給B,就可以將其分配給IEnumerable<B>類型的變量。在你的情況,這意味着如果你有,例如,其採取的方法的IEnumerable<IFoo<T>>還將接受IEnumerable<IFooTwo<T>>因爲IFooTwo<T> : IFoo<T>

但是,如果你想擁有,比如說,一類MyFoo<T> : IFoo<T>IEnumerable<MyFoo<T>>型的,有沒有自動執行該操作的方法。這是因爲完全有可能有IEnumerable<IFoo<T>>的有效實現,這不是IEnumerable<MyFoo<T>>的實現。您應該將此要求視爲設計氣味,並儘量避免它。

+0

我現在看到的問題1,我可以測試如果T:IEquatable 並更改我的IEquatable > .Equals實現功能。如果它是另一個接口而不是IEquatable呢? 但對於問題2,我無法列舉我想要做的FooTwo 類爲FooTwo 。 (例如'foreach(FooTwo t x in)'將會失敗,x'FooTwo ' –

+0

@ CelestinSaint-Loup那麼你總是可以在'FooTwo'聲明中添加':IEnumerable >'顯然不會當'x'工作時(在你的例子中)有靜態類型'IFooTwo'而不是'FooTwo',但這是不可能的。 –

+0

@ CelestinSaint-Loup但是有一個原因,你發現這些東西很難 - 你正在嘗試對照類型系統而不是使用它,你應該檢查你的設計,試着看看你能否擺脫這些要求 –

相關問題