Type Inference

May 3, 2011 at 12:43 AM

I've been thinking about it for a while but never got a chance to dive into details of type inference. Lately I've made some tests and realized that it won't be so easy. Before I describe why I would like to present my ideal API:

Let's define a method we want to make asynchronous:

private static string Method1()
    return "Method1";

Currently the only way to create AsyncFunc for this method is:

AsyncFunc<string> func;
func = new AsyncFunc<string>(Method1);

It's fine but why we have to specify type twice? Wouldn't it be better if we could use type inference and write something like:

AsyncFunc<string> func;
func =  AsyncFunc.Create(Method1);

Create method I used here would be generic, static method on static AsyncFunc class. Although this syntax looks fine, when we try to compile it we will get error:

The type arguments for method 'System.AsyncFunc.CreateF<T,TResult>(System.Func<T,TResult>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.   

When I was looking for the solution I realized that there is non. The problem is related to how the C# compiler works. Type Inference happens before overloads resolution. Therefore Method1 doesn't give enough information for the type inference to work. Eric Lippert describes it thoroughly on this blog (http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx)


Although I was disappointed I didn't give up. I created signature that's fine for the compiler. The trick is to move return value as a out parameter to the method. Then everything is fine for compiler:

public class AsyncFunc
    public static void Create<TResult>(Func<TResult> func, out AsyncFunc<TResult> result)
        result = new AsyncFunc<TResult>(func);

Then this API can be used like that:

AsyncFunc<string> func;
AsyncFunc.Create(Method1, out func);

Although it works, it isn't recommended to use out parameters. I think they should be used only when it's necessary and changes in the syntax for object creation isn't the case. If you think different please let me know. I would also like to hear about any alternative approaches to this problem.