Why is this method group conversion ambiguous in C# 7.2 and lower?

270 views Asked by At

Given the following class:

public class Foo {
    public Foo(int i, double d) {
        Integer = i;
        Double = d;
    }
    public int Integer {get;}
    public double Double {get;}

    private static Random rand = new Random();
    public static Foo CreateRandom() => new Foo(rand.Next(1,101), rand.NextDouble());
}

As well as this usage:

void Main()
{
    var items = Enumerable.Range(0, 50)
                          .Select(_ => Foo.CreateRandom());

    Console.WriteLine(items.Sum(GetInteger)); // Fine
    Console.WriteLine(items.Sum(GetDouble)); // Ambiguous
    Console.WriteLine(items.Sum(x => x.Double)); // Also fine
    Console.WriteLine(items.Sum((Func<Foo,double>)GetDouble)); // Cast required? Why?

    int GetInteger(Foo item) => item.Integer;
    double GetDouble(Foo item) => item.Double;
}

I am trying to figure out why it is that the GetDouble delegate conversion is considered ambiguous, and what exactly makes it different in this context from the labmda expression and the cast to the anonymous delegate.

Edit: It looks like this does not affect C# 7.3, but does affect versions 7.2 and lower. Versions before local methods were added can be affected by making the GetInteger and GetDouble static.

1

There are 1 answers

0
Fabjan On BEST ANSWER

What's new in C# 7.3

The following enhancements were made to existing features:

  • You can test == and != with tuple types.
  • You can use expression variables in more locations.
  • You may attach attributes to the backing field of auto-implemented properties.
  • Method resolution when arguments differ by in has been improved.
  • Overload resolution now has fewer ambiguous cases.

The last fix was for this issue. Before that compiler had more difficulties resolving overloads.

Here is a link to the source.