2013-10-08 38 views
16

我第一次看到一位同事在執行對象池時做這件事。他將這個類作爲參數傳遞給泛型基類。這個基類放出了合併代碼。是否讓類將自身作爲參數傳遞給泛型基類邪惡?

奇怪的是,基類會知道它的孩子。這在每個正常情況下被認爲是不好的做法。但在這種情況下,父母只是避免編寫重複代碼的技術解決方案。基類不會被任何其他代碼引用。

這種結構的一個缺點是它「燒傷基礎類」。您不能在層次結構中引入泛型基類。這個問題可能超出了這個話題。

下面是一個可以想到例如:

public abstract class Singleton<T> where T : class 
{ 
    public static T Instance { get; private set; } 

    public Singleton() 
    { 
     if (Instance != null) 
      throw new Exception("Singleton instance already created."); 
     Instance = (T) (object) this; 
    } 
} 

public class MyClass : Singleton<MyClass> 
{ 
} 

改進代碼:

public abstract class Singleton<T> where T : Singleton<T> 
{ 
    public static T Instance { get; private set; } 

    public Singleton() 
    { 
     if (Instance != null) 
      throw new Exception("Singleton instance already created."); 
     Instance = (T) this; 
    } 
} 

public class MyClass : Singleton<MyClass> 
{ 
} 

回答

14

否;這是一個衆所周知的模式,稱爲CRTP
它在C++中作爲虛擬方法的替代方法特別有用。

您可以在.Net框架中看到它IComparable<T>IEquatable<T>

增強堅固性,您應該添加where T : Singleton<T>

+0

你最後一句話讓我心動。 class SingleTon where T:Singleton ?這不需要你無限遞歸(每個T必須是Singleton ,其中T將再次是單例等) – Kristof

+0

增加了SLaks代碼改進。第一行確實讓你頭暈目眩。 –

+0

@Kristof參見上面的例子:'public MyClass:Singleton '。這種類型,「MyClass」IS-A'Singleton '所以它的工作原理。儘管如此,它仍然有點腦筋急轉彎。 –

3

SLaks是正確的 - 這是一個有用的模式,通常當你想在其中是強類型的,以你的派生類的基類提供代碼。

您通常還會爲泛型參數添加一個類型約束,以指示泛型類型必須從抽象類型繼承。添加此約束的語法看起來是遞歸的,但不要驚慌 - 它不會被遞歸計算,而只是確保唯一有效的泛型類型是派生類。

例如,假設您經營茶和咖啡混合業務。把咖啡和咖啡,茶和茶混合在一起是有道理的,但是你要確保你不能混合咖啡和茶。然而,因爲它們都是飲料,所以你想用同樣的方式對它們進行建模。

public abstract class Beverage<T> where T : Beverage<T> 
{ 
    public abstract T Blend(T drink1, T drink2); 
} 

public class Tea : Beverage<Tea> 
{ 
    public override Tea Blend(Tea drink1, Tea drink2) 
    { 
     // Blend tea here. 
    } 
} 
public class Coffee : Beverage<Coffee> 
{ 
    public override Coffee Blend(Coffee drink1, Coffee drink2) 
    { 
     // Blend coffee here. Although coffee is nasty, so 
     // why you'd want to is beyond me. 
    } 
} 

閱讀關於CRTP時,值得記住的是C++模板只是表面上類似於C#泛型。關鍵的區別在於模板實際上是編譯時工作的代碼生成工具,而運行時支持C#泛型。

此外,編寫這樣的代碼會降低可讀性。因此,雖然肯定會有這種情況是正確的,但您應該考慮一下您嘗試解決的問題,並確定是否有更直接的方法。

+0

MyClass.Instance會編譯。 –

+0

已編輯適當。 –

+2

當然,'公共課咖啡:飲料'是一個法律聲明。這很容易搞砸了。 – Brian

相關問題