I'm trying to write a method like this:
public static T Test<T>()
{
if (typeof(T)==typeof(string))
return "1241";
// do something else
}
but I can't seem to figure out how to pull it off. I want to return values depending on the type of T that the method was invoked with. I need to return strings, int's, custom classes, List etc.
The actual usecase is some custom serialization code where it is essential that the deserializing code knows the type of the object it should produce.
Clarification: the example above gives the following error: Cannot convert string to type T
The ideal solution would work on value types and reference types, and would not include a dummy parameter for overload resolution.
I'm starting to doubt if that ideal solution exists though.
Thanks, Lucas
The intermediate cast to object
isn't ideal, but something like this should do the trick:
public static T Test<T>()
{
if (typeof(T) == typeof(string))
return (T)(object)"1241";
// do something else
}
You have to cast the return value to T, e.g. something like this for reference types:
public static T Test<T>() where T : class
{
if (typeof(T)==typeof(string))
return "1241" as T;
return default(T);
}
Beware! The solution below does not work (verified using the Mono gmcs
C# compiler).
However, it should work by my reading of the C# standard, since the overload resolution should favour the non-generic version of the method when possible. The relevant section in ECMA-334 is 25.1.7: “Overloading in generic classes”. Furthermore, Eric Lippert seems to say so, too, in a blog posting.
Feedback would be appreciated: why doesn't this work as expected?
You have got unrelated types and unrelated behaviour: this code screams “use overloading!”
Generics would be appropriate for unrelated types, yet identical (or highly similar) behaviour.
Do this (complete test program to reproduce behaviour):
using System;
class TestClass {
public static T Test<T>() {
return TestWith(default(T));
// do something else
}
public static string TestWith(string dummy) {
// Used only for `string`.
return "string";
}
public static T TestWith<T>(T dummy) {
// Used for everything else.
return dummy;
}
static void Main() {
Console.WriteLine("Expected \"0\", got \"{0}\"", Test<int>());
Console.WriteLine("Expected \"string\", got \"{0}\"", Test<string>());
}
}
Compiled with gmcs
, this yields:
Expected "0", got "0"
Expected "string", got ""
Here, the parameter serves only for the disambiguation of the overloaded call. Explicit generic parameters cannot be used here since one of the functions (the string
specialization) isn't generic.
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