C# CS0121-Roslyn、CSC v12.0和mono编译器的不一致过载解决方案

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

我注意到,在将Xamarin项目上的代码拉入运行Visual Studio 2015.2的Win 10框中之后,针对特定编译器执行了一些奇怪的重载解析。我的好奇心最终让我找到了Jon Skeet和Eric Lippert的关注点,并在这个问题上提供了真正的信息

也就是说,我想看看这两个编译器之间的这种差异的最低复制成本是多少,我所做的是创建以下两个代码段

我将从Roslyn的成功案例开始: ​

使用系统;
公共静态类程序
{
公共静态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更好的转换目标

这里的问题似乎是,考虑到组中竞争方法之间的参数数量相同,非无效返回类型始终是首选。从前面提到的情况来看,曾经的编译器错误现在是可以接受的,假设它是一个单一的非void返回类型,与预期的传入方法组完全匹配然而,奇怪的是,即使组中的void方法是目标方法接受参数的唯一逻辑匹配,返回类型的方法也会优先,并且无法编译。

因此,方法组似乎考虑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>");}
}