Action和Func参数的歧义性

20

这段代码怎么可能

TaskManager.RunSynchronously<MyObject>(fileMananager.BackupItems, package);

导致编译错误

The call is ambiguous between the following methods or properties:
'TaskManager.RunSynchronously<MyObject>(System.Action<MyObject>, MyObject)' and
'TaskManager.RunSynchronously<MyObject>(System.Func<MyObject, bool>, MyObject)'

当操作的签名为

public void BackupItems(MyObject package)

而"ambiguous"的方法是

static class TaskManager
{
    public static void RunSynchronously<TInput>(Action<TInput> task, TInput param)
    {
        Task.Factory.StartNew(() => task(param));
    }

    public static bool RunSynchronously<TInput>(Func<TInput, bool> task, TInput param)
    {
        return Task.Factory.StartNew(() => task(param)).Result;
    }
}

在我看来,这些方法之间存在很大的差异。我错过了什么吗?

编辑:

除了已经接受的答案,我刚刚在一个类似的问题中找到了一个解决方案。这是链接


当你说“抛出异常”时,你是指“导致编译错误”吗? - svick
@svick 是的,你说得对。抱歉误导了你。谢谢,我已经编辑了帖子。 - Ondrej Janacek
3个回答

26

方法的返回类型不是其签名的一部分,因此在解析正确的重载时,编译器只查看方法的参数。

最简单的解决方案是不使用隐式方法组转换。以下所有内容都可以编译:

TaskManager.RunSynchronously<MyObject>(
    x => fileMananager.BackupItems(x), package);

TaskManager.RunSynchronously<MyObject>(
    (Action<MyObject>)fileMananager.BackupItems, package);

TaskManager.RunSynchronously<MyObject>(
    new Action<MyObject>(fileMananager.BackupItems), package);
第一个方法是最优雅的,但由于额外重定向的缘故,它也是唯一一个具有轻微运行时性能影响的方法。然而,这种影响非常小,以至于您实际上不用担心。

这适用于所有方法还是仅适用于lambda? - Alessandro D'Andria
@AlessandroD'Andria:你具体是什么意思? - Daniel Hilgarth
我没有意识到这一点。有没有办法设计我的 TaskManager.RunSynchronously 方法,以便我不需要显式转换? - Ondrej Janacek
@OndrejJanacek:现在,我不知道怎么做,抱歉。 - Daniel Hilgarth
@DanielHilgarth 好的,这不是本问题的主题。但如果您找到解决方案,请更新您的答案并让我知道。顺便问一句,当“package”应该是参数时,第一个解决方案中神奇变量“x”代表什么? - Ondrej Janacek
@OndrejJanacek:那里没有魔术变量。这是一个简单的lambda表达式。当调用lambda时,x将具有您传递给lambda作为参数的任何值。如果不清楚,请务必阅读有关lambda的资料。 - Daniel Hilgarth

2

现在的另一个可能的解释是:

代码是为 C# 7.3 版本编写的(默认情况下由 MSBuild 16.x 使用,对应 VS2019),但尝试使用早期版本的 C# 进行构建(这是 MSBuild 15.x 的默认版本,对应 VS2017)。

早期版本的 C# 会抛出此错误,但在 C# 7.3 中可以正确解析重载。


0
我遇到了同样的问题,解决方法是:
var r = RunSynchronously<bool>(x =>
{
    return true;
}, true);

RunSynchronously<bool>(x =>
{
}, true);

现在,为什么编译器不能做到这一点呢???


1
你可以使用 x => true 代替 x => { return true; } - Decade Moon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接