Hemme's Blog

Stories from behind the keyboard

  • RSS
  • Twitter
  • Linkedin

C# generic type inference is a cool feature but you cannot use it at full power with anonymous types, without some hack. Lets see what I mean...

Could the compiler do more?

One useful feature about C# generics is the ability of the compiler to recognize (precisely to infer) the type of the type parameter(s) when you invoke a generic method, based on the type of the corresponding input parameter(s).

For instance, let's consider the following class:

class ClassA
{
  public void Method<T>(T input)
  {
    //Use input in some way...
    Console.Write(input);
  }
}

You can call ClassA.Method() in this way:

Method<T>("Hello generics!");

…or without specifing the value of the T parameter:

Method("Hello generic type inference!");

This feature is most useful when you work with anonymous types, since anonymity deprives you the ability to specify the type name:

var something = new {Text="Hello generics", CanInfer=true};
MethodOne(something);

Type inference in generic classes

Unfortunately, generic type inference is not allowed during constructor invocations because the value of the type parameter is part of the definition of the class you want to instanciate. For instance, let's declare a generic class:

class ClassB<T> {  
  public ClassB(T input) {
    _Input = input; 
  }

  private readonly T _Input; 

  public Method {
    //This will use the _Input field in some way…
  } 
}

In order to instanciate ClassB<T> you have to pass an input type parameter to the constructor, like this:

var c = new ClassB<string>("Hello generics!");

c.MethodOne();

Even if the constructor gets an input parameter of type T, you are not allowed to invoke the constructor without passing explicitly the generic type. For instance, the following invocation will produce a compilation error:

var a = new {Text="Hello generics", CanInfer=false};
var c = new ClassB(a); //This line wont compile

Here comes the hack

There are situations when the lack of generic type inference for generic classes is critical. The previous example is one of them: it looks like you cannot use ClassB<T> with anonymous types at all!

Luckily you can achieve generic type inference …with a little hack! Sorriso All you need is to define a non-generic version ClassB of your generic class ClassB<T> and to implement a generic factory method like this:

static class ClassB
{
  public static ClassB<T> GetInstance<T>(T input)
  {
    return new ClassB<T>(input);
  }
}

Now you can use generic type inference at full power!

var a = new {Text="Can you infer my type?", CanInfer=true};

//Look ma, no generic type parameter!
var cba = ClassB.GetInstance(a);
cba.Method();

Enjoy.

No comments: