C# CS0121-Roslyn、CSC v12.0和mono编译器的不一致过载解决方案
我注意到,在将Xamarin项目上的代码拉入运行Visual Studio 2015.2的Win 10框中之后,针对特定编译器执行了一些奇怪的重载解析。我的好奇心最终让我找到了Jon Skeet和Eric Lippert的关注点,并在这个问题上提供了真正的信息 也就是说,我想看看这两个编译器之间的这种差异的最低复制成本是多少,我所做的是创建以下两个代码段 我将从Roslyn的成功案例开始: C# CS0121-Roslyn、CSC v12.0和mono编译器的不一致过载解决方案,c#,mono,roslyn,C#,Mono,Roslyn,我注意到,在将Xamarin项目上的代码拉入运行Visual Studio 2015.2的Win 10框中之后,针对特定编译器执行了一些奇怪的重载解析。我的好奇心最终让我找到了Jon Skeet和Eric Lippert的关注点,并在这个问题上提供了真正的信息 也就是说,我想看看这两个编译器之间的这种差异的最低复制成本是多少,我所做的是创建以下两个代码段 我将从Roslyn的成功案例开始: 使用系统; 公共静态类程序 { 公共静态void Main(){Foo(Bar);}//Outputs
使用系统;
公共静态类程序
{
公共静态void Main(){Foo(Bar);}//Outputs Func
公共静态无效条(字符串输入){Console.WriteLine(输入);}
公共静态字符串栏(){return string.Empty;}
公共静态void Foo(动作输入){input(“动作”);}
公共静态void Foo(Func输入){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"); }
}
使用系统;
公共静态类程序
{
公共静态void Main(){Foo(Bar);}
公共静态void Bar(){Console.WriteLine(“Action”);}
公共静态void Foo(操作输入){input();}
公共静态void Foo(Func输入){Console.WriteLine(“Func”);}
}
对所用编译器版本的最后总结:
罗斯林:1.2.0.60425
v12:12.0.31010.0
单声道:4.2.3.0
所以我在这一点上有点不知所措,我的理解是,规范对于如何处理事情的这一特定部分有点模糊。让特定于编译器的代码有效显然不是最好的,因此我可能只需要请求团队成员提供lambda表达式以避免方法组的歧义,或者至少是显式转换
罗斯林案件对我来说特别奇怪,因为它的决定似乎是最武断的选择。如有任何其他见解,将不胜感激
编辑:
我确实找到了一个额外的代码片段,它将在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"); }
}
使用系统;
公共静态类程序
{
公共静态void Main(){Foo(Bar);}
公共静态字符串栏(){return string.Empty;}
公共静态void Foo(操作栏){Console.WriteLine(“bar”);}
公共静态void Foo(Func输入){Console.WriteLine(“Func”);}
}
好吧,我暂时放弃了这一点,做了一些其他的事情,稍微简化了一些用法,我想我已经确定了以下几点,通过查找
7.5.3.5更好的转换目标
给定两种不同类型的T1和T2,T1是更好的转换目标
比T2如果
- 存在从T1到T2的隐式转换
- T1是委托类型D1或表达式树类型
表达式T2是委托类型D2或表达式树
类型表达式D1有一个返回类型S1和以下类型之一
持有:
- D2无效返回
- D2具有返回类型S2,S1是比S2更好的转换目标
因此,方法组似乎考虑Roslyn下的选择返回类型,只要给定相等的输入参数,方法组中的一个可能的成员只有空类型
以外的返回类型。//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"); }
}
//Roslyn很好,Mono没那么好
使用制度;
公共静态类程序
{
公共静态void Main(){Foo(Bar);}//Outputs Func
公共静态字符串栏(){return string.Empty;}
公共静态空白条(字符串s1、字符串s2、字符串s3){}
公共静态空栏(字符串s1、字符串s2){}
公共静态无效条(字符串s1){}
//取消对编译失败的检查
//公共静态void Foo(Func输入){}
公共静态void Foo(操作输入){}
公共静态void Foo(操作输入){}
公共静态void Foo(操作输入){}
公共静态void Foo(Func输入){Console.WriteLine(“Func”);}
}
虽然Mono似乎走了相反的方向,但将返回类型视为选择过程的一部分,这似乎意味着§7.6.5.1的Mono实现与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>");}
}
//单声道很好,Rosyln没有那么好
使用制度;
公共静态类程序
{
公共静态void Main(){Foo(Bar);}//Outputs Func
公共静态字符串栏(字符串s1、字符串s2、字符串s3){返回“失败”;}
公共静态字符串栏(字符串s1、字符串s2){返回“失败”;}
公共静态字符串栏(字符串s1){返回“失败”;}
公共静态字符串栏(){return“Pass”;}
//取消对编译失败的检查
//公共静态void Foo(Func输入){Console.WriteLine(“”;}
公共静态void Foo(Func输入){Console.WriteLine(“Func”);}
公共静态void Foo(Func输入){Console.WriteLine(“Func”);}
公共静态void Foo(Func输入){Console.WriteLine(“Func”);}
公共静态void Foo(Func输入){Console.WriteLine(“Func”);}
}
由于Eric Lippert先前概述的原因,这两种方法在以前的编译器版本中都不起作用。这
//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>");}
}