c# - 罗斯林未能编鳕鱼

将项目从VS2013迁移到VS2015之后,项目不再构建。 以下LINQ语句中发生编译错误:

static void Main(string[] args)
{
    decimal a, b;
    IEnumerable<dynamic> array = new string[] { "10", "20", "30" };
    var result = (from v in array
                  where decimal.TryParse(v, out a) && decimal.TryParse("15", out b) && a <= b // Error here
                  orderby decimal.Parse(v)
                  select v).ToArray();
}

编译器返回错误:

错误CS0165使用未分配的本地变量&#39; b&#39;

是什么导致这个问题? 是否可以通过编译器设置来修复它?

ramil89 asked 2019-08-13T13:22:19Z
4个解决方案
111 votes

是什么导致了这个问题?

看起来像编译器错误给我。 至少,确实如此。 虽然&&&&表达式是动态计算的,但我希望编译器仍然能够理解,当它达到bool时,from string v in arrayb都是明确分配的。 即使你可以在动态类型中提出奇怪的想法,我也期望在评估两个TryParse之后只评估a <= b

然而,事实证明,通过操作员和转换技巧,如果您足够狡猾,那么表达式&&&&bool而不是from string v in array)完全可行。 有关Neal Gafter的巧妙示例,请参阅Roslyn错误报告。

使用&&更加困难 - 当操作数是动态时所涉及的语义更难描述,因为为了执行重载解析,您需要评估操作数以找出涉及的类型,这可能是违反直觉的。 然而,Neal再次提出了一个示例,表明编译器错误是必需的...这不是一个错误,它是一个错误修复。 为了证明这一点,Neal获得了大量的赞誉。

是否可以通过编译器设置来修复它?

不,但有其他方法可以避免错误。

首先,你可以阻止它变得动态 - 如果你知道你只会使用字符串,那么你可以使用&&或给范围变量&&一种类型bool(即from string v in array)。 那将是我的首选。

如果你真的需要让它保持动态,那就给&&一个值来开始:

decimal a, b = 0m;

这不会造成任何伤害 - 我们知道实际上您的动态评估不会做任何疯狂的事情,因此您在使用之前仍然会将值分配给&&,从而使初始值无关紧要。

此外,似乎添加括号也有效:

where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)

这改变了触发各种重载决策的点,并使编译器感到高兴。

还有一个问题仍然存在 - 需要澄清规范与&&运营商明确分配的规则,并声明它们仅适用于&&运算符在其常规&#34;中使用的情况。 使用两个bool操作数实现。 我将尝试确保下一个ECMA标准已经修复。

Jon Skeet answered 2019-08-13T13:24:02Z
21 votes

这似乎是Roslyn编译器中的错误,或者至少是回归。 已提交以下错误以跟踪它:

[https://github.com/dotnet/roslyn/issues/4509]

与此同时,Jon的优秀答案还有几个方面。

JaredPar answered 2019-08-13T13:24:42Z
16 votes

由于我在错误报告中接受了如此努力的学习,我将尝试自己解释一下。


想象一下T是一些用户定义的类型,隐式转换为dynamic,在truefalse之间交替,从bool开始。就编译器所知,第一个&&的第一个参数可能会评估为该类型,因此它必须 悲观。

如果,那么,它让代码编译,这可能发生:

  • 当动态绑定器评估第一个dynamic时,它会执行以下操作:
    • 评估第一个参数
    • 这是一个dynamic - 隐含地将它投射到true
    • 哦,这是dynamic,所以我们不需要评估第二个参数。
    • dynamic的结果计算为第一个参数。 (不,不是true,出于某种原因。)
  • 当动态绑定器评估第二个dynamic时,它执行以下操作:
    • 评估第一个参数。
    • 这是一个dynamic - 隐含地将它投射到true
    • 哦,它是dynamic,所以评估第二个参数。
    • ...哦废话,dynamic没有被分配。

简而言之,有特殊的&#34;明确的任务&#34; 这些规则让我们不仅要说一个变量是否被明确分配了#34; 或者&#34;没有明确分配&#34;,但如果它是&#34;在dynamic声明之后明确分配&#34; 或者&#34;在true声明&#34;之后明确分配。

这些存在使得当处理dynamictrue(以及falsebool?:)时,编译器可以检查是否可以在复杂布尔表达式的特定分支中分配变量。

但是,这些只能在表达式的同时工作。 类型保持布尔值。 当表达式的一部分是dynamic(或非布尔静态类型)时,我们不能再可靠地说表达式是truefalse - 下次我们将其转换为bool以决定采取哪个分支时,它可能已经更改了 心神。


更新:现在已经解决并记录在案:

先前编译器为动态表达式实现的明确赋值规则允许某些代码可能导致读取的变量未明确赋值。 有关此报告,请参见[https://github.com/dotnet/roslyn/issues/4509]。

...

由于这种可能性,如果val没有初始值,编译器不得允许编译该程序。 先前版本的编译器(在VS2015之前)允许该程序编译,即使val没有初始值。 罗斯林现在诊断这种尝试读取可能未初始化的变量。

Rawling answered 2019-08-13T13:27:30Z
15 votes

这不是一个错误。 有关此表单的动态表达式如何使这样的out变量未分配的示例,请参见[https://github.com/dotnet/roslyn/issues/4509#issuecomment-130872713]。

Neal Gafter answered 2019-08-13T13:27:58Z
translate from https://stackoverflow.com:/questions/31961411/roslyn-failed-to-compile-code