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.
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.
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.
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.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With