C#mono出现奇怪的编译错误

时间:2016-07-16 11:19:51

标签: c# compiler-errors mono

我有这段代码:

int? sum=Enumerable.Range(0, 1000).Sum((i) =>
        {
            if (((i % 3) == 0) && ((i % 5) == 0))
                return i;
            return null;
        });

此代码无法编译,它会生成此错误:

  

错误CS0266:无法隐式转换类型'decimal?' 'int?'。存在显式转换(您是否错过了演员?)

我将代码更改为:

int? sum=Enumerable.Range(0, 1000).Sum<int>((int i) =>
        {
            if (((i % 3) == 0) && ((i % 5) == 0))
                return i;
            return null;
        });

但编译器错误仍然存​​在。

我不明白,Enumerable.Range返回一个整数集合,显然我想要返回int的Sum? ,否则i应为decimal,正如我所说,如果我在int之前插入i并不重要。

当我sum decimal?变量时,它会编译。

我认为这可能是一个单声道错误,我在this错误列表中看不到类似内容。

所以我错过了什么或者我应该提交错误吗?

我的单声道版本是4.4.1,我的操作系统是Arch linux x64。

2 个答案:

答案 0 :(得分:1)

绝对是一个错误,因为VisualStudio附带的编译器不会发生这种情况。

单声道的解决方法似乎是返回default(int?)而不是null。

int? sum=Enumerable.Range(0, 1000).Sum((i) =>
    {
        if (((i % 3) == 0) && ((i % 5) == 0))
            return i;
        return default(int?);
    });

答案 1 :(得分:1)

这是一个精简的测试程序,用于演示BCL之外的问题:

using System;
using static System.Console;
static class Program {
  static void Test1(Func<int?> f)     { WriteLine("Test1(Func<int?>)");     }
  static void Test1(Func<decimal?> f) { WriteLine("Test1(Func<decimal?>)"); }
  static void Test2(Func<decimal?> f) { WriteLine("Test2(Func<decimal?>)"); }
  static void Test2(Func<int?> f)     { WriteLine("Test2(Func<int?>)");     }
  static void Main() {
    Test1(() => null);
    Test2(() => null);
  }
}

使用Mono(4.4)编译时,会打印:

Test1(Func<decimal?>)
Test2(Func<int?>)

使用Roslyn编译时,会打印:

Test1(Func<int?>)
Test2(Func<int?>)

在完成C#5.0语言规范时,最终应该选择哪个重载归结为 7.5.3.3从表达式更好的转换,但它没有解决这种情况。它给出了一些特定的场景,其中一个重载优于另一个,但是为了在这里工作,它需要根据它所谓的推断的返回类型进行操作。但是,null没有类型。没有推断的返回类型。这使得我们在语言规范中没有任何内容描述了使用哪个重载。

5.0语言规范说调用不明确。编译器应该生成错误。

不幸的是,语言规范并未描述Microsoft的编译器。这迫使Mono实现了试图模仿微软行为的丑陋黑客,因为拒绝编译用微软编译器编译的代码是让人们不认真对待Mono的简单方法,正如你在对这个问题的回答中所看到的那样。那些丑陋的黑客并不完美,除非规范正确描述了他们设计的语言,否则可能永远都不会。

非官方的C#6.0语言规范已在https://github.com/ljw1004/csharpspec/blob/gh-pages/README.md公开。它描述了对重载决策规则的一些调整(寻找7.5.3.3从表达式更好的转换和7.5.3.5更好的转换目标):

  • int?是一个比decimal?更好的转换目标,因为存在从int?decimal?的隐式转换,但反之亦然。
  • 因此,Func<int?>是比Func<decimal?>更好的转换目标。
  • 因此,从() => nullFunc<int?>的转化优于Func<decimal?>

6.0语言规范可能会说代码有效,而Roslyn是对的。但该语言规范尚未最终确定。

由于C#6.0语言规范还没有最终确定,Mono很难准确地实现它,而且它似乎还没有完成。

无论您将其视为Mono错误或缺少功能的解决方法,还是将其作为代码的修复程序以使其与C#5.0更兼容,结果都是相同的:使用default(int?)代替{正如史蒂夫所建议的那样,{1}}会使它发挥作用。在C#5.0中,它的工作方式是给匿名函数一个推断的返回类型null,解决所需重载的歧义。