C# mono 出现奇怪的编译器错误
strange compiler error with C# mono
我有这个代码:
int? sum=Enumerable.Range(0, 1000).Sum((i) =>
{
if (((i % 3) == 0) && ((i % 5) == 0))
return i;
return null;
});
此代码无法编译,它会生成此错误:
error CS0266: Cannot implicitly convert type 'decimal?' to 'int?'. An explicit conversion exists (are you missing a cast?)
我将代码更改为:
int? sum=Enumerable.Range(0, 1000).Sum<int>((int i) =>
{
if (((i % 3) == 0) && ((i % 5) == 0))
return i;
return null;
});
但编译器错误仍然存在。
我不明白,Enumerable.Range
returns 一个整数集合,很明显我想要 Sum
那个 returns 整数? ,否则 i
应该是 decimal
并且正如我所说,我是否在 i
之前插入 int
并不重要。
当我将 sum
设为 decimal?
变量时,它会编译。
我认为这可能是一个单声道错误,我在 this 错误列表中没有看到类似的错误。
那么我是不是遗漏了什么或者我应该提交错误?
我的单声道版本是 4.4.1,我的 OS 是 Arch linux x64.
绝对是一个错误,因为 VisualStudio 附带的编译器不会发生这种情况。
mono 的解决方法似乎是 return default(int?)
而不是 null。
int? sum=Enumerable.Range(0, 1000).Sum((i) =>
{
if (((i % 3) == 0) && ((i % 5) == 0))
return i;
return default(int?);
});
这是一个精简的测试程序,它演示了 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 更好地从表达式 转换,但它没有解决这种情况.它给出了一些特定的场景,其中一个重载比另一个更好,但要让它在这里工作,它需要根据它所谓的 推断的 return 类型 采取行动。但是,null
没有类型。没有推断的 return 类型。这使我们在描述要使用的重载的语言规范中没有任何内容。
5.0 语言规范说调用不明确。编译器应该生成一个错误。
不幸的是,语言规范没有描述微软的编译器。这迫使 Mono 实施试图模仿微软行为的丑陋黑客,因为拒绝编译确实使用微软编译器编译的代码是让人们不认真对待 Mono 的简单方法,正如您在对这个问题的回应中所看到的.那些丑陋的 hack 并不完美,而且可能永远不会完美,除非规范正确描述了他们设计的语言。
非官方的 C# 6.0 语言规范已在 public 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?>
更好的转换目标。
- 因此,从
() => null
到 Func<int?>
的转换优于 Func<decimal?>
。
6.0 语言规范可能会说代码有效,Roslyn 是正确的。但该语言规范尚未最终确定。
由于C#6.0语言规范尚未最终确定,Mono很难准确实现,目前看来还没有完成。
无论您将其视为 Mono 错误或缺失功能的解决方法,还是将其视为代码修复以使其与 C# 5.0 更兼容,结果都是一样的:改用 default(int?)
null
,正如史蒂夫所建议的那样,将使它起作用。在 C# 5.0 中,它的工作方式是通过为匿名函数提供一个 int?
的推断 return 类型,以有利于所需重载的方式解决歧义。
我有这个代码:
int? sum=Enumerable.Range(0, 1000).Sum((i) =>
{
if (((i % 3) == 0) && ((i % 5) == 0))
return i;
return null;
});
此代码无法编译,它会生成此错误:
error CS0266: Cannot implicitly convert type 'decimal?' to 'int?'. An explicit conversion exists (are you missing a cast?)
我将代码更改为:
int? sum=Enumerable.Range(0, 1000).Sum<int>((int i) =>
{
if (((i % 3) == 0) && ((i % 5) == 0))
return i;
return null;
});
但编译器错误仍然存在。
我不明白,Enumerable.Range
returns 一个整数集合,很明显我想要 Sum
那个 returns 整数? ,否则 i
应该是 decimal
并且正如我所说,我是否在 i
之前插入 int
并不重要。
当我将 sum
设为 decimal?
变量时,它会编译。
我认为这可能是一个单声道错误,我在 this 错误列表中没有看到类似的错误。
那么我是不是遗漏了什么或者我应该提交错误?
我的单声道版本是 4.4.1,我的 OS 是 Arch linux x64.
绝对是一个错误,因为 VisualStudio 附带的编译器不会发生这种情况。
mono 的解决方法似乎是 return default(int?)
而不是 null。
int? sum=Enumerable.Range(0, 1000).Sum((i) =>
{
if (((i % 3) == 0) && ((i % 5) == 0))
return i;
return default(int?);
});
这是一个精简的测试程序,它演示了 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 更好地从表达式 转换,但它没有解决这种情况.它给出了一些特定的场景,其中一个重载比另一个更好,但要让它在这里工作,它需要根据它所谓的 推断的 return 类型 采取行动。但是,null
没有类型。没有推断的 return 类型。这使我们在描述要使用的重载的语言规范中没有任何内容。
5.0 语言规范说调用不明确。编译器应该生成一个错误。
不幸的是,语言规范没有描述微软的编译器。这迫使 Mono 实施试图模仿微软行为的丑陋黑客,因为拒绝编译确实使用微软编译器编译的代码是让人们不认真对待 Mono 的简单方法,正如您在对这个问题的回应中所看到的.那些丑陋的 hack 并不完美,而且可能永远不会完美,除非规范正确描述了他们设计的语言。
非官方的 C# 6.0 语言规范已在 public 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?>
更好的转换目标。 - 因此,从
() => null
到Func<int?>
的转换优于Func<decimal?>
。
6.0 语言规范可能会说代码有效,Roslyn 是正确的。但该语言规范尚未最终确定。
由于C#6.0语言规范尚未最终确定,Mono很难准确实现,目前看来还没有完成。
无论您将其视为 Mono 错误或缺失功能的解决方法,还是将其视为代码修复以使其与 C# 5.0 更兼容,结果都是一样的:改用 default(int?)
null
,正如史蒂夫所建议的那样,将使它起作用。在 C# 5.0 中,它的工作方式是通过为匿名函数提供一个 int?
的推断 return 类型,以有利于所需重载的方式解决歧义。