No boxing or type parameter conversion for generic Type parameter

24,680

Solution 1

For this scenario you'll need to loosen generic restrictions of CreateRequest.

public static T CreateRequest<T>()
    where T : new()
{
    if(!typeof(Request).IsAssignableFrom(typeof(T)))
        throw new ArgumentException();

    var result = new T();
    Request request = (Request)(object)result;
   // ...
   // Assign default values, etc.
   // ...
   return result ;
}

It might be painful because you lose compile time verification of this parameter.

Or if you want to use CreateRequest method elsewhere then create non-generic overload for this scenario only.

public static object CreateRequest(Type requestType)
 {
    if(!typeof(Request).IsAssignableFrom(requestType))
        throw new ArgumentException();

    var result = Activator.CreateInstance(requestType);
    Request request = (Request)result;
   // ...
   // Assign default values, etc.
   // ...
   return result ;
}

Solution 2

You have declared that the type of T is Request in CreateRequest method; on the otherhand, in Map method you do not have such constraint. Try changing the declaration of Map to:

public T Map<F, T>(F value, T toValue)
where T : Request, new()
where F : new()
Share:
24,680
Lukasz Lysik
Author by

Lukasz Lysik

.NET Developer

Updated on August 06, 2020

Comments

  • Lukasz Lysik
    Lukasz Lysik almost 4 years

    I have the following helper method:

    public static T CreateRequest<T>()
        where T : Request, new()
    {
        T request = new T();
        // ...
        // Assign default values, etc.
        // ...
        return request;
    }
    

    I want to use this method from the inside of another method in another helper:

    public T Map<F, T>(F value, T toValue)
        where T : new()
        where F : new()
    {
        if (typeof(T).BaseType.FullName == "MyNamespace.Request")
        {
            toValue = MyExtensions.CreateRequest<T>();
        }
        else
        {
            toValue = new T();
        }
    }
    

    But then I get the error:

    The type 'T' cannot be used as type parameter 'T' in the generic type or method 'MyExtensions.CreateRequest()'. There is no boxing conversion or type parameter conversion from 'T' to 'MyNamespace.Request'.

    Is there a way to cast the type "T", so that CreateRequest would use it without problems?

    EDIT:

    I know I can do two things:

    • loosen constraints on CreateRequest or
    • tighten contraints in Map.

    But I can't do the first, because in CreateRequest I user properties of Request class, and I can't do the second, because I use other types (that don't inherit from Request) with Map function.

  • Lukasz Lysik
    Lukasz Lysik almost 12 years
    The problem is I use Map function with types, that don't inherit from Request, so I can't set this contraint.
  • Admin
    Admin almost 12 years
    why is this double-cast needed? (Request)(object)result;
  • Admin
    Admin almost 12 years
    nice catch with the .IsAssignableFrom! way better than string-comparison!
  • daryal
    daryal almost 12 years
    Then you may try removing Request constraint from CreateRequest function.
  • Rafal
    Rafal almost 12 years
    Dual cast is for compiler to tell him that you know what your doing and you take responsibility for it. Without it it wont work and the if above ensures that this will work.
  • Admin
    Admin almost 12 years
    ah yes ... forgot about that - it's true that there's no possibility to direct-cast T to something other than object :) but you could go for class and use the as-operator :)
  • Rafal
    Rafal almost 12 years
    I tend to use as only if it is fallowed by if(sth != null) - save cast where I expect it to fail sometimes.