2013-03-14 77 views
1

考慮下面的比賽:參數類型該類

public interface ITree<X> 
{ 
    ... 
    ITree<X> Union(ITree<X> other); 
    ... 
} 

的想法是,我要實現幾種類型的樹。但是,Union()方法僅適用於如果您嘗試將的兩棵樹組合在一起的。但是,上面的類型簽名不會強制執行此限制。

所以,我的問題是:我如何寫一個類型簽名Union()使得other參數必須具有同一類型this? (顯然,如果類型不匹配,我可以做一個動態運行時測試並拋出一個異常,但是如果可以完成的話,我會在編譯時檢查它)。

+2

@JLRishe - 這不會是因爲如果他們都執行「ITree 」,您可以將「RedBlackTree 」與「SplayTree 」聯合起來。 – Lee 2013-03-14 19:20:54

+0

爆炸!你是對的。我認爲這個問題是指「X」。 – JLRishe 2013-03-14 19:23:05

+0

@Lee我不確定這是泛型系統可以用任何有用的方式表達的類型約束。 (只是沒有在界面中的方法。) – millimoose 2013-03-14 19:24:12

回答

2

表達這一點並不是一種特別乾淨的方式,這是使用接口的結果,因爲沒有辦法知道ITree<X>的實現類型。最好的方法可能是創建另一個類/接口,限制了混凝土樹類型並執行操作()你需要:

public interface ITreeUnion<T, X> where T : ITree<X> 
{ 
    T Union(T left, T right); 
} 

你那麼有這個接口類型的實例傳遞給你需要的地方進行所需的操作。

如果你真的需要Union去,你可以使用一個循環模板的接口上:

public interface ITree<T, X> where T : ITree<T, X> 
{ 
    T Union(T other); 
} 

public class RedBlackTree<T> : ITree<RedBlackTree<T>, T> 
{ 
    public RedBlackTree<T> Union(RedBlackTree<T> other) 
    { 
    } 
} 
+0

我曾嘗試寫'T '等術語,但編譯器不喜歡它。我沒有想過試圖使用'T:ITree '約束;這很巧妙! – MathematicalOrchid 2013-03-14 19:54:34

+0

與此相關的是,你顯然可以將'Union'作爲一種「擴展方法」,使它看起來不那麼奇怪。 (雖然這本身並不給我想要的動態綁定。) – MathematicalOrchid 2013-03-21 08:18:55

0

爲什麼你需要界面呢?簡單地實現對樹的每個實施Replace方法:

public class RedBlackTree<T> { 
    public RedBlackTree<T> Union(RedBlackTree<T> other) { ... } 
} 

public class SplayTree<T> { 
    public SplayTree<T> Union(SplayTree<T> other) { ... } 
} 

既然你用的ITree每個執行交易時尋找編譯時的安全性,我認爲你只需要處理的具體類型。當然,如果需要,您可以使用其他方法ITree<T>

0

不知何故,以下actually compiles

public interface ITree<TSelf, TItem> where TSelf : ITree<TSelf, TItem> 
{ 
    TSelf Union(TSelf other); 
    // ... 
} 

public class AvlTree<TItem> : ITree<AvlTree<TItem>, TItem> { 
    public AvlTree<TItem> Union(AvlTree<TItem> other) { 
     return other; 
    } 
} 

當然,這不是特別有用,因爲再你必須聲明變量爲ITree<AvlTree>,此時你可能不會使用該接口。使用C#泛型時,通用類型參數的值必須在某個時刻已知,才能確定泛型類型。

1

根據您的需求,您需要一個Union()的通用聲明。

  • 接口

    public partial interface ITree<X> { 
        T Union<T>(T other) where T: ITree<X>; 
    } 
    
  • 示例類

    public partial class TreeOfObject: ITree<object> { 
        public T Union<T>(T other) where T: ITree<object> { 
         return default(T); // sample only; shuold be implemented yourself 
        } 
    } 
    
    public partial class TreeOfInt: ITree<int> { 
        public T Union<T>(T other) where T: ITree<int> { 
         return default(T); // sample only; shuold be implemented yourself 
        } 
    } 
    
  • 測試

    public static partial class TestClass { 
        public static void TestMethod() { 
         var x=new TreeOfObject(); 
         var y=new TreeOfInt(); 
    
         var xx=x.Union(x); 
         var yy=y.Union(y); 
    
         var xy=x.Union(y); // won't compile 
         var yx=y.Union(x); // won't compile 
        } 
    } 
    
+0

Ooo,這很有趣......我不知道一個方法的重寫可以將新的類型約束添加到通用參數。 – MathematicalOrchid 2013-03-14 22:49:10

+0

您不是覆蓋方法,而是實現接口。無論在何處定義類型,通用方法定義都是無論如何,如果使用與類定義相同的類型參數聲明,編譯器甚至會警告您。 – 2013-03-14 22:59:21