为什么C#的重载解析在Func <T,T>和Action <T>之间不起作用?

Mar*_*dle 12 c# linq

因此,IEnumerable的一个相当常见的扩展方法,运行:

public static IEnumerable<T> Run<T>(this IEnumerable<T> source, Action<T> action)
{
    foreach (var item in source)
    {
        action(item);
        yield return item;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用它时,例如,DbSet.Add:

invoice.Items.Run(db.InvoiceItems.Add);
// NB: Add method signature is
// public T Add(T item) { ... }
Run Code Online (Sandbox Code Playgroud)

...编译器抱怨它有错误的返回类型,因为它期望一个void方法.因此,为Run添加一个重载,它接受一个Func而不是Action:

public static IEnumerable<T> Run<T>(this IEnumerable<T> source, Func<T, T> action)
{
    return source.Select(action).ToList().AsEnumerable();
}
Run Code Online (Sandbox Code Playgroud)

现在编译器抱怨"以下方法之间的调用是模糊的......"

所以我的问题是,当Run方法的Action重载对方法组无效时,怎么会导致歧义?

k.m*_*k.m 5

Eric和Jon已经在回答这个问题时对此进行了解释.长话短说 - 这就是C#编译器的工作原理; 确切地说,在处理方法组转换时,决定将转换为哪个委托使用重载解析,这不会占用帐户中的返回类型:

这里的原则是确定方法组可转换性需要使用重载决策从方法组中选择方法,并且重载决策不考虑返回类型.

在您的例子编译器同时看到Action<T>Func<T, T>作为最佳匹配Add.这增加了两个可能的选择,因为它需要一个 - 发出适当的错误.