Tutorial :I know the typeof(T) but the compiler doesn't. How to fix?



Question:

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


Solution:1

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  }  


Solution:2

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);  }  


Solution:3

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.


Solution:4

Try

public static T Test<T>() where T : class  {    if (typeof(T) == typeof(string)) return "asdf" as T;  // do something else    // do something else          }  


Solution:5

Can you use ChangeType?

public static T Test<T>()  {      if (typeof(T)==typeof(string))          return (T)Convert.ChangeType("1234", typeof(T), CultureInfo.InvariantCulture);      return default(T);  }  


Solution:6

I found the solution:

public static T Test<T>()  {    if (typeof(T) == typeof(string))       return (T)(object)"1241";    // this works.        // do something else  }  

Thanks for all the answers.


Solution:7

public static T Test<T>()  {    if (typeof(T)==typeof(string))       return (T)Convert.ChangeType("1241", typeof(T));      return default(T);  }  

I've not tested it though :-)


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »