Почему вызов неоднозначен? 'Task.Run(Action)' и 'Task.Run(Func <task>)"

Учитывая следующий код:

public void CacheData()
{
    Task.Run((Action)CacheExternalData);
    Task.Run(() => CacheExternalData());

    Task.Run(CacheExternalDataTask);

    Task.Run(CacheExternalData);
}

public Task CacheExternalDataTask()
{
    // Long running code
    return Task.FromResult("Data");
}

public void CacheExternalData()
{
    // Long running code
}

Почему Task.Run(CacheExternalData) неоднозначен? А Task.Run(CacheExternalDataTask) нет?

При вызове Task.Run с CacheExternalData я бы подумал, что компилятору было ясно, что метод не возвращает Task и он должен решить Action?

Ответ 1

Это должно быть ясно, но спецификация языка никогда не говорила, что несоответствующие типы возврата будут иметь какой-либо эффект во время разрешения перегрузки. Из-за этого не было правила, в котором говорилось, что он предпочитает Action над Func<Task>. Если бы Action было выбрано, конечно, это сработало бы. Если бы Func<Task> был выбран, то, конечно, вы получили бы ошибку. Но, чтобы выбрать либо, разрешение перегрузки должно быть успешным, и это не учитывает это.

Предполагается, что это исправлено с новым разрешением перегрузки в С# 7.3.