C# 一个函数的函数在一个方向上工作,而不是在另一个方向上

C# 一个函数的函数在一个方向上工作,而不是在另一个方向上,c#,functional-programming,C#,Functional Programming,我正在尝试编写一个函数,将函数作为其参数之一,这是我以前做过很多次的任务。这很好: int RunFunction(Func<int,int> f, int input) { return f(input); } int Double(int x) { return x*2; } // somewhere else in code RunFunction(Double,5); int运行函数(函数f,int输入){ 返回f(输入); } 整数倍(整数x){ 返回x

我正在尝试编写一个函数,将函数作为其参数之一,这是我以前做过很多次的任务。这很好:

int RunFunction(Func<int,int> f, int input) {
    return f(input);
}
int Double(int x) {
    return x*2;
}

// somewhere else in code
RunFunction(Double,5);
int运行函数(函数f,int输入){
返回f(输入);
}
整数倍(整数x){
返回x*2;
}
//代码中的其他地方
运行函数(双,5);
但这不起作用:

public static class FunctionyStuff {
    public static int RunFunction(this Func<int,int> f, int input) {
        return f(input);
    }
}

// somewhere else in code
Double.RunFunction(5);
公共静态类函数stuff{
公共静态int运行函数(此函数为f,int输入){
返回f(输入);
}
}
//代码中的其他地方
双运行函数(5);

知道为什么第一个有效而第二个无效吗?

第一个版本正在执行方法组转换,作为“参数到参数”匹配的一部分。扩展方法不会发生这种转换。lambda表达式也是如此-您无法编写:

((int x) = > x * 2).RunFunction(10);
要么

C#4规范的第7.6.5.2节给出了扩展方法调用的详细信息。它首先要求方法调用采用以下形式之一:

expr.identifier ( )
expr.identifier ( args )
expr.identifier < typeargs > ( )
expr.identifier < typeargs > ( args )
expr.identifier()
表达式标识符(args)
expr.identifier()
expr.identifier(args)
表达式的类型(
expr
)随后用于此规则:

扩展方法Ci.Mj符合以下条件:

  • [……]
  • 存在从expr到Mj第一个参数类型的隐式标识、引用或装箱转换
规范的注释版本包括Eric Lippert的以下注释:

此规则确保使扩展
double
的方法不会同时扩展
int
。它还确保在匿名函数或方法组上未定义任何扩展方法

“被调用,就好像它们是扩展类型上的实例方法一样”


在您的例子中,
Double
不是一个实例,所以您不能对它调用扩展方法。

也许您还应该解释为什么扩展方法和lambda表达式不会发生这种情况。这是因为它们没有特定的委托类型
Func
和假设的
MyIntentDelegate
可能具有相同的签名,但类型不同,因此编译器无法知道要转换为哪一种。因此,如果我没有弄错的话,在第一个版本中,有一个从
Method
Func
的隐式转换?@Joe:比这更微妙。方法组转换不是标识、引用或装箱转换。请看我的编辑。我认为这个解释虽然在技术上完全正确,但对于没有阅读过C#规范的人来说,很难理解。我仍然认为应该提到,“方法组”和“匿名函数”是特殊的编译时类型,它们本身并不是自动委托类型。它可以通过显示您可以对委托调用扩展方法来澄清这一点,例如
newfunc(x=>2*x).MyExtensionMethod()
,演示从lambda到委托类型的转换必须首先进行。@Timwi:我希望尝试向委托类型添加扩展方法的人已经对方法组的功能有所了解。也许我太有希望了。。。