-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
The lambda improvements proposal includes inferring delegate types for lambdas and method groups, creating the possibility of breaking changes in overload resolution.
Example 1
Two overloads in the default method group M, one with a generic parameter type, the other with a delegate type parameter. In C#9, M(F) binds to M(Action<string> a).
If a delegate type is inferred for F of Action<object>, overload resolution will bind to the generic overload M<Action<object>>(Action<object> t) instead.
using System;
class Program
{
static void M<T>(T t) { }
static void M(Action<string> a) { }
static void F(object o) { }
static void Main()
{
M(F); // C#9: M(Action<string>)
}
}See sharplab.io
Example 2
Two overloads in the method group c.M, one with an object type parameter on the containing type, the other with a delegate type parameter as an extension method. In C#9, the calls to c.M(expr) bind to the extension method.
If delegate types are inferred for the method group and lambda expression, those expressions are implicitly convertible to object and overload resolution will bind the calls to the overload on the containing type instead.
using System;
class Program
{
static void Main()
{
var c = new C();
c.M(Main); // C#9: E.M(object x, Action y)
c.M(() => { }); // C#9: E.M(object x, Action y)
}
}
class C
{
public void M(object y) { }
}
static class E
{
public static void M(this object x, Action y) { }
}See sharplab.io
Possible solution
- Prefer binding lambda or method group arguments using the target type (the parameter type) rather than the inferred delegate type of the lambda expression or method group.
- If extension methods should be considered, and binding of the method group from the containing type or any inner extension method scope used the inferred type for lambda or method group arguments, continue searching outer extension method scopes for an overload that binds using the parameter type.