Restricting a generic type parameters to have a specific constructor

后端 未结 3 2042
时光取名叫无心
时光取名叫无心 2020-11-30 07:44

I\'d like to know why the new constraint on a generic type parameter can only be applied without parameters, that is, one may constraint the type to have the parameterless c

3条回答
  •  抹茶落季
    2020-11-30 08:29

    If one wants to have a method with a generic type T whose instances can be created using a single int parameter, one should have the method accept, in addition to type T, either a Func or else a suitably-defined interface, possibly using something like:

    static class IFactoryProducing
    {
        interface WithParam
        {
            ResultType Create(PT1 p1);
        }
        interface WithParam
        {
            ResultType Create(PT1 p1, PT2 p2);
        }
    }
    

    (the code would seem nicer if the outer static class could be declared as an interface, but IFactoryProducing.WithParam seems clearer than IFactory (since the latter is ambiguous as to which type is the parameter and which is the result).

    In any case, whenever one passes aroud type T one also passes around a suitable factory delegate or interface, one can achieve 99% of what one could achieve with parameterized constructor constraints. The run-time cost can be minimized by having each constructable type generate a static instance of a factory, so it won't be necessary to create factory instances in any sort of looping context.

    BTW, beyond the cost of the feature, there would almost certainly be some substantial limitations which would make it less versatile than the workaround. If constructor constraints are not contravariant with regard to parameter types, it may be necessary to pass around a type parameter for the exact type required for the constructor constraint, in addition to the actual type of the parameter to be used; by the time one does that, one might as well pass around a factory. If they are contravariant, then one runs into trouble resolving which constructor should be called if a generic type has constraint new(Cat, ToyotaTercel), and the actual type just has constructors new(Animal, ToyotaTercel) and new(Cat, Automobile).

    PS--To clarify the problem, contravariant constructor constraints lead to a variation of the "double diamond" problem. Consider:

    T CreateUsingAnimalAutomobile() where T:IThing,new(Animal,Automobile)
    { ... }
    
    T CreateUsingAnimalToyotaTercel() where T:IThing,new(Animal,ToyotaTercel)
    { return CreateUsingAnimalAutomobile(); }
    
    T CreateUsingCatAutomobile() where T:IThing,new(Cat,Automobile)
    { return CreateUsingAnimalAutomobile(); }
    
    IThing thing1=CreateUsingAnimalToyotaTercel(); // FunnyClass defined in question
    IThing thing2=CreateUsingCatAutomobile(); // FunnyClass defined in question
    

    In processing the call to CreateUsingAnimalToyotaTercel(), the "Animal,ToyotaTercel" constructor should satisfy the constraint for that method, and the generic type for that method should satisfy a constraint for CreateUsingAnimalAutomobile(). In processing the call to CreateUsingCatAutomobile(), the "Cat,Automobile" constructor should satisfy the constraint for that method, and the generic type for that method should satisfy the constraint for CreateUsingAnimalAutomobile().

    The problem is that both calls will invoke a call to the same CreateUsingAnimalAutomobile() method, and that method has no way of knowing which constructor should be invoked. Contravariance-related ambiguities aren't unique to constructors, but in most cases they're resolved through compile-time binding.

提交回复
热议问题