6

In my application, I have code similar to following:

class Program
    {
        static void Main(string[] args)
        {
            Method(uri => Task.FromResult(uri));
        }

        static void Method(Func<Uri, Uri> transformer)
        {
            throw new NotImplementedException();
        }

        static void Method(Func<Uri, Task<Uri>> transformer)
        {
            throw new NotImplementedException();
        }
    }

As expected, running this code calls the second overload of 'Method', the one expecting a function delegate that returns a task. However, if i change the code to avoid using the anonymous method in Main:

class Program
    {
        static void Main(string[] args)
        {
            Method(Method2);
        }

        static Task<Uri> Method2(Uri uri)
        {
            return Task.FromResult(uri);
        }

        static void Method(Func<Uri, Uri> transformer)
        {
            throw new NotImplementedException();
        }

        static void Method(Func<Uri, Task<Uri>> transformer)
        {
            throw new NotImplementedException();
        }
    }

The C# compiler now complains that my call to 'Method' is ambiguous. What am i missing?

richzilla
  • 40,440
  • 14
  • 56
  • 86
  • 1
    you are not passing a Uri to Method2. – Sam Axe Aug 27 '15 at 08:20
  • @SamAxe he doesn't mean to. He's trying to convert a *method group* (`Method2`) to a delegate (`Func>`) – dcastro Aug 27 '15 at 08:26
  • Possibly because `TResult` in `Func` is covariant. – haim770 Aug 27 '15 at 08:28
  • as resharper suggests. cast `Method((Func>) Method2);` – M.kazem Akhgary Aug 27 '15 at 08:32
  • 1
    @M.kazemAkhgary, ReSharper suggest that to resolve the ambiguity. The question is why is there ambiguity at all as clearly there's no implicit conversion from `Func` to `Method2`. – haim770 Aug 27 '15 at 08:34
  • @haim770 its because of return type `Task`. seems compiler does not even look in to it to resolve this ambiguity._ or maybe Task it self returns Uri? – M.kazem Akhgary Aug 27 '15 at 08:37
  • 3
    @richzilla This is a dupe indeed, and the answer is here: "The principle here is that determining method group convertibility requires selecting a method from a method group using overload resolution, and **overload resolution does not consider return types**." – dcastro Aug 27 '15 at 08:40

1 Answers1

1

The long answer is at https://stackoverflow.com/a/2058854/1223597 (as richzilla pointed out).

The short answer is that the C# compiler team chose to make method group conversions (like Method(Method2)) ignore the return type (here of Method2). This gives them flexibility in how Expression trees are parsed. Unfortunately that means the compiler cannot implicitly choose between your 2 Method signatures.

When doing a lambda conversion, (Method(uri => Task.FromResult(uri))), the compiler team doesn't need to worry about expression tree parsing, so they do consider return types.

Community
  • 1
  • 1