Могу ли я создать универсальный объект в универсальном классе, где класс создаваемого объекта имеет ограничения на параметр универсального типа? - PullRequest
2 голосов
/ 08 января 2012

У меня есть общий интерфейс,

   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
      }
   }

и декоратор, который украшает ICalculator:

   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 подчиняется ограничению T: ISpecificInterface , хотя я проверяю его во время выполнения.Может ли компилятор быть прав, или он отклоняет код только потому, что он недостаточно умен?

Есть ли способ присвоить компонентному полю SpecificAndFastCalculator ?

Насколько я вижу, у меня есть следующие варианты:

  • Написать специальный декоратор для наличия SpecificAndFastCalculator компонентов, который, я думаю, превосходит цель иметь декораторы,
  • Как-нибудь использовать магию отражения (я понятия не имею, как)
  • Удалить ограничение T: ISpecificInterface , документировать его и надеяться на лучшее.

Есть ли другой способ?На данный момент я выбираю третий вариант (удаление ограничения), что бы вы предложили?

Ответы [ 2 ]

2 голосов
/ 08 января 2012

Это должно работать, если вы измените конструктор 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 голосов
/ 08 января 2012

Вы должны иметь возможность определять SpecificAndFastCalculator без общих ограничений вообще, поскольку во время выполнения вы гарантируете, что он соответствует ISpecificInterface.

Вам, конечно, потребуется выполнить приведение во время выполнения SpecificAndFastCalculator к ICalculator<T>, и SpecificAndFastCalculator уже должно реализовать ICalculator<T> для данного T.

Например, если T == Int32, и у вас уже есть SpecificAndFastInt32Calculator, определенный как:

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

Преобразование этого экземпляра в ICalculator будет компилироваться и работать во время выполнения.

...