Stupid .NET Tricks #12

May 15, 2008 by Craig

Disclaimer: There may, in fact, be a good reason for the following .NET behavior. However, if there is, it’s certainly not clear to me. I pose a question at the bottom; dear lazyweb, please explain.

.NET’s type inference lets you avoid specifying the type of a generic parameter on a method call some, but not all, of the time. Consider the following infrastructure:

public String getSomeString() {
  return "Some String";
}

public T returnTheValue<T>(T value) {
  return value;
}

public delegate T Factory<T>();

public T createSomeValue<T>(Factory<T> factory) {
  return factory();
}

The following code works fine:

Console.WriteLine(returnTheValue("A String"));

.NET is smart enough to know that, since you’re passing in a String for T, it can assume that String is used for T elsewhere in the method (including the return type), and so it doesn’t require you to explicitly state that returnTheValue is using String for T, like so:

Console.WriteLine(returnTheValue<String>("A String"));

The above code does work, and if you specify a non-compatible type (ex: int), then you get an error. However, it’s not necessary due to type inference.

The following code also works:

Console.WriteLine( returnTheValue( getSomeString() ) );

There’s no difference between using a literal and calling a method (they’re both dealing with values).

The following does not work:

Console.WriteLine( createSomeValue( getSomeString ) );

Here we’re not passing a value, but passing a method that will create/return a value. In this case, the .NET compiler returns the following error message:

The type arguments for method ‘createSomeValue<T>( Factory<T> )’ cannot be inferred from the usage. Try specifying the type arguments explicitly.

“Specifying the type arguments explicitly” means doing this, which works:

Console.WriteLine( createSomeValue<String>( getSomeString ) );

What I don’t understand is why the type inference works in one case and not the other. We know that getSomeString() satisfies Factory<String>, and thus we know that the return value is a String. If returnSomeValue() can infer its generic type parameter is String based on the String argument, why can’t createSomeValue() infer that it’s generic type parameter is String based on its Factory<String> argument? It already knows for sure that it’s getting a Factory; it just needs to know what type of Factory.

Is there some inherent limitation to the .NET type inference system that makes it impossible to know this? Or is this simply that the .NET implementors didn’t carry the concept one step further?


1 Comment »

  1. [...] http://www.craigslinkedlist.com/posts/stupid_dotnet_tricks_12 asks Hoosgot, [...]

    Pingback by Stupid .NET Tricks #12 — May 15, 2008 @ 2:06 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment