Friday, April 8, 2011

How to copy between generic declared types with value type constraints

I have a generic method that copies values between value types. The following approaches give a design time error, even with the struct constraint. Any idea how I can copy or cast between the values?

    private Ttgt MyMethod<Tsrc,Ttgt>(Tsrc SourceObject) 
        where Tsrc:struct
        where Ttgt:struct
    {
        //Error:cannot implictly convert type 'Tsrc' to 'Ttgt'
        Ttgt returnObject = SourceObject; 

        //Error:Cannot convert type 'Tsrc' to 'Ttgt'
        Ttgt returnObject = (Ttgt)SourceObject; 

        return returnObject;
    }
From stackoverflow
  • //Error:Cannot convert type 'Tsrc' to 'Ttgt'

    You cannot convert between arbitrary types, unless there is an accessible conversion operator.

  • The two are defined as different types. Even though they are both structs, they are not the same types.

    Define both souce and target as the same type:

    private T MyMethod<T>(T source, T target)
    {
    
  • Given that there is a registered type converter for the types that you're trying to convert between a little reflection magic could do the trick:

    private Ttgt MyMethod<Tsrc,Ttgt>(Tsrc sourceObject) 
        where Tsrc:struct where  Ttgt:struct    
    {    
        Type targetType = typeof(Ttgt);
        TypeConverter tc = TypeDescriptor.GetConverter(targetType);
        Ttgt returnObject = (Ttgt)tc.ConvertTo(sourceObject, targetType);
        return returnObject;    
    }
    

    But out of the box it would be of very limited use since there is no converter between bool and int for example. What problem are you trying to solve?

    I also discovered another question with some crazy conversion code in it.

    Edit: Your comment makes it clear that you are trying to perform object to object mapping between domain objects and some kind of view/contract model. Have you looked at AutoMapper?

    Jon Simpson : I am writing a recursive object-to-object mapper. to seperate the contract classes from the underlying business logic classes in a WCF implementation. The implementation classes are near identical to the contract but I don't want to introduce a dependency between the two.
    mike nelson : This should say: Type targetType = typeof(Ttgt);
    PHeiberg : Thanks. Updated variable names to be correct.
  • This is "By Design." You are attempting to cast between two unrelated value types. This will never succeed and therefore it is flagged as an error.

    This will be true of all value typse because they are implicitly sealed. In order for a cast between TSrc -> Ttgt to succeed, there must be a class hierarchy relationship between the two types. This cannot be because all value types are sealed hence there is no way one can derive from the other.

    The only way this could succeed is if one had a custom conversion operator between the types. This may be the case. However when dealing with generic types, custom conversion operators will not be processed.

  • The Convert class exists for this exact purpose.

    private Ttgt MyMethod<Tsrc, Ttgt>(Tsrc SourceObject)
        where Tsrc : struct
        where Ttgt : struct
    {
        return (Ttgt) Convert.ChangeType(SourceObject, typeof(Ttgt));
    }
    

    Also note that you could do this:

        return (Ttgt) (object) SourceObject;
    

0 comments:

Post a Comment