Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

generics

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

like image 787
Lucas Avatar asked Jun 23 '09 10:06

Lucas


3 Answers

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
}
like image 80
LukeH Avatar answered Sep 28 '22 07:09

LukeH


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);
}
like image 45
M4N Avatar answered Sep 28 '22 08:09

M4N


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.

like image 23
Konrad Rudolph Avatar answered Sep 28 '22 07:09

Konrad Rudolph