我有一个铸造问题。
public void Test(int a = 0) { }
System.Action d = Test;
这段代码在团结中很有效。
但是visual studio 2015无法编译它。
CS0123“测试”没有超载匹配委托“行动”
为什么???
答案 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
是一个表达式列表,每个表达式都归类为一个变量,并且具有中相应参数的类型和修饰符(ref
或out
)D
的形式参数列表 - 类型为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();