Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using generic constraints with value types

I am experimenting with fluent extension methods.

I have the following simple extension method to perform a safe cast.

     public static T As<T>(this Object source)
         where T : class
     {
         return source as T;
     }

This worked well, but when I tried to make it intuitive to use valuetypes with an overload

     public static T As<T>(this ValueType source)
         where T : struct
     {
         return (T)source;
     }

I ran into problems. The method resolution logic always chooses the first method above, and gives a syntax error (accurately) that the struct is not a class.

Is there a way to handle the above, or should I go the route of removing the constraint while testing for and handling all types in the same method?

==== Edit: to answer questions ====

I am compiling this against the 3.5 framework. I'm not really trying to accomplish anything in particular; this is just an experiment with the above. My interest was piqued and I threw together some code.

I'm not particularly concerned with it remaining a 'safe' cast. That is how it started, and can be kept safe with default() -- but that's not really the focus of the question and code to ensure 'safeness' would just obscure.

As to the expressiveness, no value.As<int>() is not any more expressive than (int)value; but why should the user of the method have to 'just know' it only works with reference types? My trying to work it in was more about the expected behavior of the method than expressive writing.

The code snippet value.As<DateTime>(), gives the error "The type 'System.DateTime' must be a reference type in order to use it as parameter 'T' in the generic type or method ....As(object)". From the error message I see it is resolving to use the top method above as it is the one requiring the reference type.

like image 361
David Culp Avatar asked Oct 06 '11 15:10

David Culp


People also ask

What are generic type constraints?

C# allows you to use constraints to restrict client code to specify certain types while instantiating generic types. It will give a compile-time error if you try to instantiate a generic type using a type that is not allowed by the specified constraints.

What does the generic constraint of type interface do?

Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter.

How do you indicate that a class has a generic type parameter?

A generic type is declared by specifying a type parameter in an angle brackets after a type name, e.g. TypeName<T> where T is a type parameter.


1 Answers

In .NET 4, the second overload is chosen based on your code sample. (Also just tested against .NET 3.5, same result.)

int myInt = 1;
long myLong = myInt.As<long>(); // chooses ValueType version

However, this only gets us to the scene of the next crash. The (T)source; results in an invalid cast exception. You could get around that by writing the method as

public static T As<T>(this ValueType source)
    where T : struct
{
    return (T)Convert.ChangeType(source, typeof(T));
}

However, I wonder what you're actually looking to achieve, as I do not see the immediate benefit. (And for that matter, this isn't safe like the source as T object version.) For example, how is

long myLong = myInt.As<long>();

Any more expressive or easier to use than

long myLong = (long)myInt;
like image 146
Anthony Pegram Avatar answered Nov 02 '22 07:11

Anthony Pegram