在将Xamarin项目上的代码拉入运行Visual Studio 2015.2的Win 10盒子中的Xamarin项目中,我已经注意到奇怪的编译器特定的重载决策执行。我的好奇心最终导致我this post,这得益于Jon Skeet和Eric Lippert的关注,并且在这个问题上提供了很多信息。
那就是说,我想要看看这两个编译器之间的差异最小复制故事是什么,我设法做的是创建以下两个片段。
我将从Roslyn的成功案例开始:
using System;
public static class Program
{
public static void Main() { Foo(Bar); } // Outputs Func
public static void Bar(string input) { Console.WriteLine(input); }
public static string Bar() { return string.Empty; }
public static void Foo(Action<string> input) { input("Action"); }
public static void Foo(Func<string> input) { Console.WriteLine("Func"); }
}
Mono的工作原理:
using System;
public static class Program
{
public static void Main() { Foo(Bar); }
public static void Bar() { Console.WriteLine("Action"); }
public static void Foo(Action input) { input(); }
public static void Foo(Func<string> input) { Console.WriteLine("Func"); }
}
最后回顾使用的编译器版本:
罗斯林:1.2.0.60425v12:12.0.31010.0
mono:4.2.3.0
所以我现在已经超出了我的深度,我的理解是规范对事情的处理方式有点模糊。拥有特定于编译器有效的代码显然不是最好的,因此我可能只需要请求团队成员提供lambda表达式以避免对方法组的歧义,或者至少是显式的强制转换。
Roslyn案对我来说特别奇怪,因为看起来它的决定是最随意的选择。任何额外的见解将不胜感激。
编辑:
我确实找到了一个可以在Mono和Roslyn上成功编译但在v12编译器上失败的附加代码片段:
using System;
public static class Program
{
public static void Main() { Foo(Bar); }
public static string Bar() { return string.Empty; }
public static void Foo(Action bar) { Console.WriteLine("BAR"); }
public static void Foo(Func<string> input) { Console.WriteLine("Func"); }
}
答案 0 :(得分:2)
好吧,我离开了这一段时间,做了一些其他事情,简化了一些用法,我认为我已经确定了以下内容,并帮助找到了this in the specifications.
7.5.3.5更好的转化目标
鉴于T1和T2两种不同的类型,T1是更好的转换目标 如果
,则为T2
存在从T1到T2的隐式转换
T1是委托类型D1或表达式树类型 表达式T2是委托类型D2或表达式树 类型表达式,D1具有返回类型S1和以下之一 成立:
D2无效返回
D2的返回类型为S2,S1是比S2更好的转换目标
这里的问题似乎是,如果组中竞争方法之间的参数数量相同,则非void返回类型将始终是首选。因此,从前面提到的Eric Lippert's example来看,曾经是编译器错误的东西现在是可以接受的,假设它是一个完全匹配预期的传入方法组的单个非void返回类型。 但是,奇怪的是,即使组中的void方法是目标方法接受参数的唯一逻辑匹配,返回类型的方法也是首选,无法编译。 < / p>
所以方法组似乎确实考虑了Roslyn下选择的返回类型,只要给定相等的输入参数,方法组中只有一个可能的成员具有除void之外的返回类型
//Fine in Roslyn, not so much in Mono
using System;
public static class Program
{
public static void Main() { Foo(Bar); } // Outputs Func
public static string Bar() { return string.Empty; }
public static void Bar(string s1, string s2, string s3) { }
public static void Bar(string s1, string s2) {}
public static void Bar(string s1) { }
//untick for compile failure
//public static void Foo(Func<int> input) { }
public static void Foo(Action<string, string, string> input) { }
public static void Foo(Action<string, string> input) { }
public static void Foo(Action<string> input) { }
public static void Foo(Func<string> input) { Console.WriteLine("Func"); }
}
虽然Mono似乎走向了相反的方向,而是将返回类型视为选择过程的一部分,这似乎意味着§7.6.5.1的单声道实现与Roslyns不同。
//Fine in mono, not so much in Rosyln
using System;
public static class Program
{
public static void Main() { Foo(Bar); } // Outputs Func<string>
public static string Bar(string s1, string s2, string s3) { return "Fail"; }
public static string Bar(string s1, string s2) { return "Fail"; }
public static string Bar(string s1) { return "Fail"; }
public static string Bar() { return "Pass"; }
// untick for compile failure
// public static void Foo(Func<string,string,string,string> input) { Console.WriteLine("<string,string,string,string>"); }
public static void Foo(Func<string> input) { Console.WriteLine("Func<string>"); }
public static void Foo(Func<int> input) { Console.WriteLine("Func<int>"); }
public static void Foo(Func<decimal> input) { Console.WriteLine("Func<decimal>"); }
public static void Foo(Func<char> input) {Console.WriteLine("Func<char>");}
}
由于Eric Lippert之前概述的原因,两者都不适用于之前的编译器版本。至少,这对我来说是有益的,虽然我真的不知道我学到了什么。我想不要重载方法组,如果你这样做,请确保它对两个编译器都很好。