2012-01-08 114 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