Skip to content

Overload resolution and inferred lambda / method group delegate type: potential breaking change #4674

@cston

Description

@cston

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

  1. 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.
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions