如何将可选参数方法转换为c#中的委托

时间:2017-05-24 05:56:02

标签: c# unity3d

我有一个铸造问题。

public void Test(int a = 0) { }

System.Action d = Test;

这段代码在团结中很有效。

但是visual studio 2015无法编译它。

  

CS0123“测试”没有超载匹配委托“行动”

为什么???

3 个答案:

答案 0 :(得分:5)

当调用带有可选参数的方法时,它实际上被编译为带有参数值的调用,这些参数值由方法声明的默认值确定。

如果你有一个像这样声明和使用的方法:

public void Foo(String x = "foo", Int32 y = 123) {
    // do something
}

public void Bar() {
    Foo();
}

然后编译它,并查看程序集中生成的CIL,你会看到Bar实际上是这样做的:(而不是编译器用编译的CIL和调用约定做一些伏都教) ,例如C风格的可变函数)

public void Bar() {
    Foo("foo", 123);
}

(这也解释了为什么默认值必须是编译时常量(因为它们基本上是逐字地放在调用代码中),你应该注意,如果你改变了可选参数的值,那么一个程序集中的默认值,如果不重新编译调用程序集,则将继续使用旧值(就像public const一样)。)

我的观点是,带有可选参数的方法仍然是正式多参数方法,这就是为什么具有参数子集的委托不能绑定到它的原因。

所以在你的情况下......

所以你需要提供另一个方法重载,它是一个真正的零参数,或者将它包装在一个匿名函数中:

public void Test(Int32 a = 0) {}
public void Test() {}

Action d = Test;

或者:

Action d = () => Test();

答案 1 :(得分:1)

我很惊讶它在Unity中运作 - 它不应该。这听起来像是一个Mono编译器错误。

C#5规范并不清楚它应该如此,但是从即将到来的ECMA C#5标准的草案中,从方法组转换的条款 - 强调我的:

  
      
  • 选择单个方法M,对应于E(A)形式的方法调用,并进行以下修改:      
        
    • 参数列表A是一个表达式列表,每个表达式都归类为一个变量,并且具有中相应参数的类型和修饰符(refoutD的形式参数列表 - 类型为dynamic的参数除外,其中相应的表达式的类型为object,而不是dynamic
    •   
    • 所考虑的候选方法只是那些适用于其正常形式的方法,并且不会省略任何可选参数。因此,如果候选方法仅适用于其扩展形式,或者如果其中一个或多个可选参数在D中没有相应参数,则会忽略候选方法。
    •   
  •   

最简单的解决方法是使用lambda表达式,如Dai所说:

Action d = () => Test();

答案 2 :(得分:0)

当使用委托进行类型检查时,编译器显然会忽略可选参数的"可选"并认为它们是必需的。

您可以声明自己的委托类型来解决此问题:

public delegate void MyDel(int i = 1); // this 1 here can be any number. It does not seem to matter
//...
MyDel d = Test;
d();

或者,您只需添加一点() =>即可在lambda中调用Test

Action d = () => Test();