简体   繁体   English

带有泛型方法的C#MonoTouch方法重载和带有默认参数的非泛型方法

[英]C# MonoTouch method overload with Generic method and Non-generic method with default argument

..and a side of fries. ..和炸薯条的一面。

I have a codebase that I'm compiling for both Windows and MonoTouch. 我有一个正在为Windows和MonoTouch编译的代码库。 In the wee hours of the morning I coded something like this contrived example which compiles on MonoTouch but fails on Windows: 在早上的凌晨,我编写了类似以下示例的代码,该示例在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");
}

On MonoTouch, this compiles and runs, printing: 在MonoTouch上,它将编译并运行并打印:

AA

On Windows, this example gives a compile-time error: 在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'.

The C# spec on 7.4.2 Overload Resolution says that an 7.4.2.1 Applicable function member must have an identical number of arguments: 关于7.4.2重载分辨率的C#规范指出, 7.4.2.1适用的函数成员必须具有相同数量的参数:

The number of arguments in A is identical to the number of parameters in the function member declaration. A中的参数数量与函数成员声明中的参数数量相同。 7.4.2.1 7.4.2.1

So it would seem the MonoTouch compiler is considering default arguments when searching for applicable function members, but the Windows compiler is not. 因此,看起来MonoTouch编译器在搜索适用的函数成员时正在考虑默认参数,而Windows编译器则没有。 So the candidate function members are: 因此,候选函数成员为:

// 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; 

So, is this a bug in the Applicable Function Member search on MonoTouch, or should the Windows compiler consider the default-parameterized non-generic method as valid? 那么,这是否是MonoTouch上“适用功能成员”搜索中的错误,还是Windows编译器应将默认参数化的非泛型方法视为有效?

Cheers, cm 干杯,厘米

EDIT After dlev 's answer, I tested both the constrained and unconstrained generic methods, and it appears the Mono compiler chooses the correct method in the unconstrained case. 编辑dlev回答之后,我测试了受约束的和不受约束的泛型方法,并且在不受约束的情况下,Mono编译器似乎选择了正确的方法。 In the constrained case, it appears that the Mono compiler is either considering the constraint or backtracking to find an alternative when the constraint fails. 在受约束的情况下,似乎Mono编译器正在考虑约束,或者在约束失败时回溯以寻找替代方案。

The problem/bug reduces to: 问题/错误减少为:

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"); }

On both Windows and MonoTouch, foo correctly prints B . 在Windows和MonoTouch上, foo均可正确打印B But bar fails to compile on Windows yet prints X on MonoTouch. 但是bar无法在Windows上编译,但仍在MonoTouch上打印X

EDIT2 For those interested, my solution was to remove the default parameters and require explicit invoke. EDIT2对于那些感兴趣的人,我的解决方案是删除默认参数并需要显式调用。 In my actual system, the type constraint specifies two interfaces, so I can't easily change the generic call to exec(IFace t) { ... } . 在我的实际系统中,类型约束指定了两个接口,因此我无法轻松地将对exec(IFace t) { ... }的通用调用更改。 I suppose I could refactor, but this is the meat of my system and the following solves my current compile problems: 我想我可以重构,但这是我系统的重点,以下内容解决了我当前的编译问题:

void exec(string a) { exec(a,0); }
void exec(string a, int b) { ... }
void exec<T>(T t) where T : IFace, IFace2 { ... }

Double Cheers, cm 双打气,厘米

This line, from section 7.5.3.2 in the spec suggests that this is a bug in the Mono compiler: 规范中7.5.3.2节的这一行表明这是Mono编译器中的错误:

Otherwise if all parameters of MP have a corresponding argument whereas default arguments need to be substituted for at least one optional parameter in MQ then MP is better than MQ. 否则,如果MP的所有参数都有一个对应的参数,而MQ中的默认参数需要替换至少一个可选参数,则MP比MQ更好。

In other words, if you have to substitute a value for an optional parameter to make an applicable method call legal, then that method is considered a worse match then one that does not require such a substitution. 换句话说,如果必须用一个值替代一个可选参数以使适用的方法调用合法,则该方法被认为是较差的匹配,然后不需要这种替换。

Also, the MS C# compiler does not back-track . 而且, MS C#编译器不会回溯 Once a method is determined to be the best per the overload resolution rules, compilation continues under that assumption. 一旦根据重载解析规则确定了最佳方法,编译将在该假设下继续进行。 If later analysis determines that the selected method results in an error (say because the substituted generic argument violates a constraint) then you are told about that error. 如果以后的分析确定所选方法导致错误(例如,因为替换的泛型参数违反了约束),则会提示您该错误。

And yes, constraints are not part of the signature , so overload resolution does not consider the constraint on T . 是的,约束不是签名的一部分 ,因此重载解析不考虑对T的约束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM