2012-01-08 200 views
2

我有一個通用的接口,我可以在泛型類中創建一個泛型對象,其中要創建的對象的類對泛型類型參數有約束嗎?

public interface ICalculator<in T> 
    { 
     void Calculate(T input); 
    } 

一般的計算器,

public class GeneralCalculator<T> : ICalculator<T> 
    { 
     public void Calculate(T input) 
     { 
     bla bla 
     } 
    } 

特定的計算只適用於某些類型的作品,

public class SpecificAndFastCalculator<T> : ICalculator<T> where T : ISpecificInterface 
    { 
     public void Calculate(T input) 
     { 
     bla bla 
     } 
    } 

和裝飾ICalculators一個裝飾:

public class CalculatorDecorator<T> : ICalculator<T> 
    { 
     private readonly ICalculator<T> component; 

     public CalculatorDecorator() 
     { 
     component = (typeof (ISpecificInterface).IsAssignableFrom(typeof (T))) 
         ? new SpecificAndFastCalculator<T>() //Compiler Error 
         : new GeneralCalculator<T>(); 
     } 

     public void Calculate(T input) 
     { 
     component.Calculate(input); bla bla 
     } 
    } 

的問題是,正如你看到的,編譯器不接受來電SpecificAndFastCalculator的構造,因爲它不知道牛逼是否服從約束T:ISpecificInterface即使我檢查它在運行 - 時間。編譯器是否合適,還是僅僅因爲它不夠聰明才拒絕代碼?

是否有任何方法將組件字段分配給SpecificAndFastCalculator

至於我可以看到我有以下選擇:

  • 寫一個特定的裝飾具有SpecificAndFastCalculator 成分,我認爲拍有裝飾的目的,
  • 使用反射魔法不知何故(我沒有任何想法如何)
  • 刪除T:ISpecificInterface約束,記錄它,並希望 爲最佳。

還有別的辦法嗎?目前我正在選擇第三個選項(刪除約束),你會建議什麼?

+1

GenericCalculator的目的是什麼,對於任何'T'甚至'T'執行'Calculate(T input)'方法是否有意義都是不可接受的,比如'new Object()'? – sll 2012-01-08 19:44:11

+0

我非常喜歡抽象我的問題,所以你認爲我的設計沒有太大意義是正確的。計算器收集「事物」發生的統計數據,事物可能是事件,狀態轉換,任何事物。它跟蹤字典中的出現次數,調用GetHashCode等,並且代價很高。現在一些類有一個唯一的int id屬性。對於這些類,我可以使用id作爲快速數組的索引。裝飾者有時需要「平滑」概率,即對於看不見的事件返回ε而不是0。希望這個清理起來。 – 2012-01-08 21:05:53

回答

2

如果你改變的CalculatorDecorator<T>構造這樣它應該工作:

public CalculatorDecorator() 
{ 
    component = (ICalculator<T>)(typeof (ISpecificInterface).IsAssignableFrom(typeof (T)) 
     ? typeof(SpecificAndFastCalculator<>) 
      .MakeGenericType(typeof(T)) 
      .GetConstructor(new Type[0]) 
      .Invoke(null) 
     : new GeneralCalculator<T>()); 
} 

這將使使用專門的實施,仍然確保所有其他地方創建的實例將使用它。

+0

這是黑魔法和危險的,有一天我會改變構造類型,因此引入一個錯誤,我也會在地獄中腐爛,但是,嘿,它的工作原理!非常感謝,我是一個快樂的人。 – 2012-01-08 21:02:28

0

您應該可以定義SpecificAndFastCalculator而不使用通用約束,因爲在運行時您將保證它符合ISpecificInterface。

你將需要運行時投SpecificAndFastCalculatorICalculator<T>,當然,和SpecificAndFastCalculator必須已經實現ICalculator<T>對於給定的T.

舉例來說,如果T ==的Int32,並且你已經有了一個SpecificAndFastInt32Calculator定義爲:

public class SpecificAndFastInt32Calculator : ICalculator<Int32> { ... } 

將此實例鑄造到ICalculator將在運行時進行編譯和工作。

+0

啊,但也可以直接創建'SpecificAndFastCalculator',而不使用'DecoratorCalculator'。在'SpecificAndFastCalculator.Calculate'內,我需要假設'T'來自'ISpecificInterface',所以我將不得不盲目地從編譯時安全轉換到運行時安全。 – 2012-01-08 20:43:16

相關問題