C# 如果添加方法不会';不要卷入模棱两可的事情
我有这门课C# 如果添加方法不会';不要卷入模棱两可的事情,c#,overload-resolution,C#,Overload Resolution,我有这门课 public class Overloaded { public void ComplexOverloadResolution(params string[] something) { Console.WriteLine("Normal Winner"); } public void ComplexOverloadResolution<M>(M something) { Console.WriteL
public class Overloaded
{
public void ComplexOverloadResolution(params string[] something)
{
Console.WriteLine("Normal Winner");
}
public void ComplexOverloadResolution<M>(M something)
{
Console.WriteLine("Confused");
}
}
它将Normal Winner
写入控制台
但是,如果我添加另一种方法:
public void ComplexOverloadResolution(string something, object somethingElse = null)
{
Console.WriteLine("Added Later");
}
我得到以下错误:
以下方法或属性之间的调用不明确:>'重载.ComplexOverloadResolution(params string[])
'和'重载.ComplexOverloadResolution(string)
'
我可以理解,添加一个方法可能会引入调用歧义,但这是已经存在的两个方法之间的歧义(params string[])
和(string)
!显然,歧义中涉及的两种方法都不是新添加的方法,因为第一种是params,第二种是泛型
这是虫子吗?规范的哪一部分说明应该是这种情况?如果从第一个方法中删除
参数,则不会发生这种情况。第一个和第三个方法都有有效的调用ComplexOverloadResolution(string)
,但如果第一个方法是public void ComplexOverloadResolution(string[]something)
,则不会有歧义
为参数对象somethingElse=null提供值使其成为可选参数,因此在调用重载时不必指定该参数
编辑:编译器正在做一些疯狂的事情。如果在第一个方法之后移动代码中的第三个方法,它将正确报告。因此,它似乎在使用前两个重载并报告它们,而没有检查正确的重载
“ConsoleApplication1.Program.ComplexOverloadResolution(参数字符串[])”和
'ConsoleApplication1.Program.ComplexOverloadResolution(字符串,对象)'
编辑2:新发现。从上述三种方法中删除任何方法都不会在两者之间产生歧义。因此,冲突似乎只有在存在三种方法时才会出现,而不管顺序如何
规范的哪一部分说应该是这样的
第7.5.3节(重载解析),以及第7.4节(成员查找)和第7.5.2节(类型推断)
请特别注意第7.5.3.2节(更好的函数成员),其中部分说明“从参数列表中删除没有相应参数的可选参数”,以及“如果M(p)是非泛型方法,且M(q)是泛型方法,则M(p)优于M(q)。”
然而,我对规范的这些部分理解不够透彻,无法知道规范的哪些部分控制着这种行为,更不用说判断它是否符合规范
如果你写信
var blah = new Overloaded();
blah.ComplexOverloadResolution("Which wins?");
或者只是写
var blah = new Overloaded();
blah.ComplexOverloadResolution();
它最终将转换为相同的方法,在方法中
public void ComplexOverloadResolution(params string[] something
这是因为params
关键字使得它与未指定参数时的情况最匹配
var blah = new Overloaded();
blah.ComplexOverloadResolution(); // will be ComplexOverloadResolution(params string[] something) function called here, like a best match.
如果您尝试添加一个或多个这样的新方法
public void ComplexOverloadResolution(string something)
{
Console.WriteLine("Added Later");
}
它将完美地编译并调用此方法,因为它是与字符串
参数调用的完美匹配。比params string[]something
强得多
您像以前一样声明了第二个方法
public void ComplexOverloadResolution(string something, object something=null);
编译器,在第一个方法和这个方法之间完全混淆,只是添加了一个。
因为它不知道他现在应该在你的电话里
var blah = new Overloaded();
blah.ComplexOverloadResolution("Which wins?");
事实上,如果您从调用中删除字符串参数,就像下面的代码一样,一切都会正确编译并像以前一样工作
var blah = new Overloaded();
blah.ComplexOverloadResolution(); // will be ComplexOverloadResolution(params string[] something) function called here, like a best match.
这是虫子吗
对
恭喜,您在重载解析中发现了一个错误。这种虫子在C#4和C#5中繁殖;它不会在语义分析器的“Roslyn”版本中重现。我已经通知了C#5测试团队,希望我们能在最终发布之前调查并解决这个问题。(一如既往,没有承诺。)
正确的分析如下。候选人包括:
0: C(params string[]) in its normal form
1: C(params string[]) in its expanded form
2: C<string>(string)
3: C(string, object)
0:C(参数字符串[])的正常形式
1:C(参数字符串[])的展开形式
2:C(字符串)
3:C(字符串、对象)
候选零显然不适用,因为string
不能转换为string[]
。剩下三个
在这三种方法中,我们必须确定一种独特的最佳方法。我们通过对剩下的三位候选人进行两两比较来做到这一点。有三对这样的。一旦我们去掉省略的可选参数,所有这些参数都有相同的参数列表,这意味着我们必须进入本规范第7.5.3.2节中所述的高级平分回合
哪一个更好,1还是2?相关的分界点是泛型方法总是比非泛型方法差。2比1差。所以2不可能是赢家
哪一个更好,1还是3?相关的分界点是:仅适用于其扩展形式的方法总是比适用于其正常形式的方法更差。因此1比3差。所以1不可能是赢家
2号还是3号,哪个更好?相关的分界点是泛型方法总是比非泛型方法差。2比3差。所以2不可能是赢家
要从一组多个适用的候选人中选择,候选人必须(1)不败,(2)击败至少一个其他候选人,以及(3)具有前两个属性的唯一候选人。候选人三未被其他候选人击败,且至少击败一名其他候选人;它是唯一具有此属性的候选者。因此,候选人三是最佳人选。它应该赢
不仅是C#4编译器出错了,正如您正确地注意到的,它还报告了一条奇怪的错误消息。编译器将重载解析分析搞错了,这有点令人惊讶。它错误地接收到错误信息完全不令人惊讶;如果无法确定最佳方法,则“模糊方法”错误启发式基本上从候选集中选择任意两种方法。它不太善于找到它
public class Overloaded
{
public void ComplexOverloadResolution(params string[] somethings)
{
Console.WriteLine("Normal Winner");
}
public void ComplexOverloadResolution<M>(M something)
{
Console.WriteLine("Confused");
}
public void ComplexOverloadResolution(string something, object somethingElse = null)
{
Console.WriteLine("Added Later");
}
}
class Program
{
static void Main(string[] args)
{
Overloaded a = new Overloaded();
a.ComplexOverloadResolution(something:"asd");
}
}