1

..还有一份薯条。

我有一个正在为 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 函数成员必须具有相同数量的参数:

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 上的 Applicable Function Member 搜索中的错误,还是 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 上编译但X在 MonoTouch 上打印。

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 { ... }

双倍干杯,厘米

4

1 回答 1

1

规范中第 7.5.3.2 节中的这一行表明这是 Mono 编译器中的错误:

否则,如果 MP 的所有参数都有对应的参数,而默认参数需要替换 MQ 中的至少一个可选参数,则 MP 优于 MQ。

换句话说,如果您必须为可选参数替换一个值以使适用的方法调用合法,那么该方法被认为是比不需要这种替换的方法更差的匹配。

此外,MS C# 编译器不会回溯. 一旦根据重载解决规则确定方法是最佳的,编译就会在该假设下继续进行。如果稍后的分析确定所选方法导致错误(例如因为替换的泛型参数违反了约束),那么您会被告知该错误。

是的,约束不是签名的一部分,所以重载决议不考虑约束T

于 2012-07-09T23:28:17.767 回答