c# - 为什么 C# 编译器不能从函数签名中推断泛型委托(delegate)?

标签 c# generics functional-programming type-inference currying

<分区>

我正在使用一个函数,该函数将两个函数作为参数,并返回一个新的组合函数:

public static Action<T> Compose<T>(Action<T> first, Action second)
{
    return new Action<T>(arg =>
    {
        first(arg);
        second();
    });
}

我注意到如果我不指定 T 编译器会报错,当向它发送静态或成员函数(而不是实际的 Action<T> 对象)时:

static void Main(string[] args)
{
    // compiler error here
    var composed = Compose(Test, () => Console.WriteLine(" world"));
    composed("hello");

    Console.ReadLine();
}

public static void Test(string arg)
{
    Console.Write(arg);
}

错误信息:

The arguments for method 'ConsoleTest.Program.Compose(System.Action, System.Action)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

我的问题:为什么不能在这里推断类型参数? Test的签名在编译时是已知的,不是吗?真的有一些功能可以代替 Test 吗? , 这会导致其签名不明确吗?

脚注:我知道我可以简单地发送 new Action<string>(Test)而不是 TestCompose (如 this question 中所述)——我的问题是“为什么”,而不是“我该怎么做”。

最佳答案

我想这可能与以下事实有关,至少从编译器的角度来看,Test实际上是一个“方法组”,直到编译器确定了它将具有的参数类型。即使组中只有一个方法也是如此(当前作用域中只有一个 Test 方法)。

观察:

var composed = Compose<object>(Test, () => Console.WriteLine(" world"));

产生错误:

The best overloaded method match for 'Compose<object>(System.Action<object>, System.Action)' has some invalid arguments

Argument 1: cannot convert from 'method group' to 'System.Action<object>'

但这很好:

var composed = Compose<string>(Test, () => Console.WriteLine(" world"));

我的猜测是编译器将方法组表达式 ( Test ) 和隐式类型的泛型方法调用 ( Compose ) 视为某种意义上的“未绑定(bind)”。从参数的类型'未绑定(bind)'签名到Compose不能完全确定从方法组中选择哪个方法,它无法确定 Compose 的类型类型参数从签名。它需要一个或另一个被“绑定(bind)”才能编译整个语句。

关于c# - 为什么 C# 编译器不能从函数签名中推断泛型委托(delegate)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19015283/

相关文章:

c# - Entity Framework Core - 更新相关集合

c# - 为什么 c# 编译器在使用具有 new() 约束的泛型类型调用 new 时发出 Activator.CreateInstance?

java - 我将如何组合 BiPredicate 和 Predicate?

python - 内置将函数应用于列表的连续成员并返回新列表的方法

php - 将静态函数分配给PHP中的变量

类型 Dictionary<string,string> 不支持 C# 比较运算符

c# - EF Core 3 使用扩展方法过滤数据

c# - 在一次性对象上未正确调用处置

c++ - 读取通用数据类型文件的函数

java - 为什么在忽略参数类型时泛型会完全禁用?