2

I have a class with the following two methods

class Foo
{
    public async Task Perform(Func<Task> func)
    {
        await func();
    }

    public async Task Perform(Func<Task<bool>> func)
    {
        await func();
    }
}

Everything works as expected when I call the methods with funcs

await foo.Perform(async () => { /* */ }); // calls first method
await foo.Perform(async () => true); // calls second method

However, if I try to call the first method (Func<Task>) with a method delegate I get the following compilation error: "Expected a method with Task ReturnTask() signature"

class Bar
{
    public async Task Call()
    {
        var foo = new Foo();

        await foo.Perform(ReturnTask); // compilation error
        await foo.Perform(ReturnTaskOfBool); // works
    }

    private Task ReturnTask()
    {
        return Task.Completed;
    }

    private Task<bool> ReturnTaskOfBool()
    {
        return Task.FromResult(true);
    }
}

Any ideas why this is? Is there some way around it, besides making the name of the methods unique?

pardahlman
  • 1,394
  • 10
  • 22
  • You can read here: http://stackoverflow.com/q/28697092/5311735 and here http://stackoverflow.com/q/2057146/5311735 – Evk Mar 07 '17 at 08:05
  • The first link in @Evk's comment doesn't look applicable, but the second is and includes a detailed explanation from the one guy who'd know. While the error message is slightly different due to minor differences in the scenario, it is essentially the same issue. The question itself calls out the work-around: just cast the method group name, e.g.: `await foo.Perform((Func)ReturnTask);` – Peter Duniho Mar 07 '17 at 08:17
  • You could also create a `Perform(Func> func)` then compiler will be able to tell them apart without casting. – Mats391 Mar 07 '17 at 08:19
  • @Mats391: how does that help? Simply adding that method only helps if you get rid of the `Perform(Func> func)` method overload as well, and if the `Perform()` method actually needs to use the return value from the task, making it a generic type parameter would, at best, a) require the `Perform()` method to use the double-cast hack (i.e. `bool result = (bool)(object)(await func());` and b) would allow the method to be called incorrectly, using `Func>` where `T` is something other than `bool`. – Peter Duniho Mar 07 '17 at 08:25
  • @PeterDuniho you can keep the `Perform()` and only replace the current bool variant with generic. The second point is true tho. If returning anything but `bool` is not desired, this wont be too good. In the given example it would not matter tho. – Mats391 Mar 07 '17 at 08:30
  • Note that your sample code will compile if you use C# 7.3 (`7.3`) or later thanks to [improved overload candidates](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7-3#improved-overload-candidates). – 0xced Mar 20 '19 at 23:12

0 Answers0