Can I create a generic object within a generic class where the class of the object to be created has constraints on the generic type parameter?

StackOverflow https://stackoverflow.com/questions/8780527

Question

I have a generic interface,

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

a general calculator,

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

a specific calculator that works only on some types,

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

and a decorator that decorates 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
      }
   }

The problem is, as you see, the compiler does not accept to call the constructor of SpecificAndFastCalculator because it doesn't know whether T obeys the constraint T : ISpecificInterface even though I check it at run-time. Can the compiler be right, or does it reject the code only because it is not smart enough?

Is there any way to assign the component field to a SpecificAndFastCalculator?

As far as I can see I have these options:

  • Write a specific decorator for having SpecificAndFastCalculator components, which I think beats the purpose of having decorators,
  • Use reflection magic somehow (I don't have any idea how)
  • Delete the T : ISpecificInterface constraint, document it, and hope for the best.

Is there any other way? For the time being I'm opting for the third option (deleting the constraint), what would you suggest?

Was it helpful?

Solution

It should work if you change the constructor of CalculatorDecorator<T> like this:

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

That will make use of the specialized implementation and still make sure all elsewhere created instances will use it as well.

OTHER TIPS

You should be able to define the SpecificAndFastCalculator without a generic constraint at all, since at runtime you are guaranteeing that it conforms to ISpecificInterface.

You are going to need to runtime-cast SpecificAndFastCalculator to ICalculator<T>, of course, and SpecificAndFastCalculator must already implement ICalculator<T> for the given T.

For instance, if T == Int32, and you already have a SpecificAndFastInt32Calculator defined as:

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

Casting an instance of this to ICalculator will both compile and work at runtime.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top