..和炸薯条的一面。
我有一个代码库,我正在为Windows和MonoTouch编译。在早上的凌晨,我编写了类似于这个人工制作的例子,它在MonoTouch上编译但在Windows上失败:
void Run()
{
// okay on both
exec("hello", 1);
// okay on MonoTouch
// compiler error on windows
exec("hello");
}
interface IFace { void foo(); }
void exec(string s, int n=0)
{
Console.Write("A");
}
void exec<T>(T t) where T:IFace
{
Console.Write("B");
}
在MonoTouch上,这会编译并运行,打印:
AA
在Windows上,此示例给出了编译时错误:
The type 'string' cannot be used as type parameter 'T' in the generic type or method 'App.Program.exec<T>(T)'. There is no implicit reference conversion from 'string' to 'App.Program.IFace'.
7.4.2 Overload Resolution上的C#规范说7.4.2.1 Applicable function member必须有相同数量的参数:
A中的参数数量与函数成员声明中的参数数量相同。 7.4.2.1
所以看起来MonoTouch编译器在搜索适用的函数成员时会考虑默认参数,但Windows编译器却没有。所以候选函数成员是:
// exec with no default parameters. not applicable because no int supplied
void exec(string,int);
// exec with default value for the second parameter.
// only considered on MonoTouch.
void exec(string,int=0);
// generic exec with string as the type, which is invalid
// due to the IFace constraint. Invalid on both platforms.
void exec<string>(string) : where T:IFace;
那么,这是MonoTouch上适用功能成员搜索中的错误,还是Windows编译器将默认参数化非泛型方法视为有效?
干杯, 厘米
修改
在dlev
的回答之后,我测试了约束和非约束泛型方法,看起来Mono编译器在无约束的情况下选择了正确的方法。在受约束的情况下,看起来Mono编译器正在考虑约束或回溯以在约束失败时找到替代方案。
问题/错误减少为:
void Run()
{
foo(1);
bar(1);
}
void foo(int a, int b = 0) { print("A"); }
void foo<T>(T t) { print("B"); }
void bar(int a, int b=0) { print("X"); }
void bar<T>(T t) where T : IFace { print("Y"); }
在Windows和MonoTouch上,foo
正确打印B
。但bar
无法在Windows上编译,但在MonoTouch上打印X
。
EDIT2
对于那些感兴趣的人,我的解决方案是删除默认参数并要求显式调用。在我的实际系统中,类型约束指定了两个接口,因此我无法轻松地将通用调用更改为exec(IFace t) { ... }
。我想我可以重构,但这是我系统的核心,以下解决了我当前的编译问题:
void exec(string a) { exec(a,0); }
void exec(string a, int b) { ... }
void exec<T>(T t) where T : IFace, IFace2 { ... }
双倍欢呼,cm
答案 0 :(得分:1)
这一行,来自规范7.5.3.2节,表明这是Mono编译器中的一个错误:
否则,如果MP的所有参数都有相应的参数 而默认参数需要替换至少一个 MQ中的可选参数,然后MP优于MQ。
换句话说,如果你必须用一个值替换一个可选参数来使一个适用的方法调用合法,那么那个方法被认为是一个不需要这种替换的方法。
此外,the MS C# compiler does not back-track。一旦根据重载决策规则确定方法是最佳的,则在该假设下继续编译。如果以后的分析确定所选方法导致错误(比如因为替换的泛型参数违反了约束),那么就会告诉您该错误。
和yes, constraints are not part of the signature,因此重载解析不会考虑T
上的约束。