Compiler not resolving to expected extension method

I noticed today when trying to convert an inline lambda function to a closure so I could use the same lambda in multiple places. This will compile to the correct extension method:

appBuilder.Use((ctx, next) => {
    return next();

That Use is an extension defined by:

public static IAppBuilder Use(this IAppBuilder app, Func<IOwinContext, Func<Task>, Task> handler);

Now if I do the same thing, but move the inline to a variable:

Func<IOwinContext, Func<Task>, Task> handler = (ctx, next) => {
        return next();

The compiler resolves to this method (not the extension):

IAppBuilder Use(object middleware, params object[] args);

What am I doing here to cause that method to change signatures?

Thanks in advance.

Jon Skeet

What am I doing here to cause that method to change signatures?

A lambda expression doesn't have a type, and is only convertible to compatible delegate and expression-tree types.

Therefore the regular IAppBuilder method with (object, params object[]) parameters is not applicable for your call with the lambda expression argument. At that point, the compiler will look for extension methods.

Compare that with the version with the handler variable - at that point, you've got an argument which is convertible to object, and it's fine for a parameter array to have no values... so the regular method is applicable.

Importantly, if the compiler finds any applicable non-extension methods, it performs overload resolution using those. Extension methods are only used when no non-extension methods are applicable.

If you had either two extension methods or two regular methods, overload resolution would determine that the one with the more specific parameter is better for this invocation than the (object, params object[]) one... but that's not the case; the two are never compared.


See more on this question at Stackoverflow