Roslyn无法编译代码

在将我的项目从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使用未分配的局部variables'b'

造成这个问题的原因 是否有可能通过编译器设置来解决它?

什么导致这个问题?

看起来像一个编译器错误给我。 至less,它的确如此。 尽pipedecimal.TryParse(v, out a)decimal.TryParse(v, out b)expression式是dynamic计算的,但我还是希望编译器能够理解,当它达到a <= bab都是肯定的分配。 即使是在dynamicinput中也可能出现的奇怪现象,我只希望在对两个TryParse调用进行评估之后评估a <= b

然而,事实certificate,通过操作和转换的棘手,有一个expression式A && B && C评估AC而不是B – 完全可行 – 如果你足够狡猾。 看看Neal Gafter的巧妙例子的Roslyn错误报告 。

使用dynamic工作更加困难 – 当操作数是dynamic的时候涉及到的语义很难描述,因为为了执行重载parsing,您需要评估操作数以找出涉及哪些types,这可能是违反直觉的。 然而,Neal再次提出了一个例子,它显示了编译器错误是必需的…这不是一个错误,这是一个错误修复 。 巨大的赞誉Nealcertificate了它。

是否有可能通过编译器设置来解决它?

不,但也有避免错误的select。

首先,你可以阻止它的dynamic – 如果你知道你只会使用string,那么你可以使用IEnumerable<string> 给范围variablesvstringtypes(即from string v in array )。 那将是我的首选。

如果你真的需要保持它的dynamic,只需给出一个值开始:

 decimal a, b = 0m; 

这不会造成任何伤害 – 我们知道, 实际上,您的dynamic评估不会做任何疯狂的事情,所以在使用它之前,您仍然会最终为b赋值,使得初始值无关紧要。

另外,似乎添加圆括号也起作用:

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

这改变了各种重载分辨率的触发点,恰巧使编译器感到高兴。

还有一个问题 – 有关&&运算符明确赋值的规范需要澄清,指出只有当&&运算符在其“常规”实现中使用了两个bool操作数时才适用。 我会尽量确定这是下一个ECMA标准的固定。

这似乎是Roslyn编译器中的一个错误,或者至less是一个回归。 以下错误已被提交以追踪它:

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

与此同时,乔恩的优秀答案有几个解决方法。

由于我在错误报告中受过很严格的训练,所以我会试着自己解释一下。


想象一下, T是一些用户定义的types,隐式转换为bool ,在falsetrue之间交替,从false开始。 据编译器知道,第一个&&dynamic第一个参数可能会评估为这种types,所以它必须是悲观的。

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

  • 当dynamic联编程序评估第一个&& ,它执行以下操作:
    • 评估第一个参数
    • 这是一个T – 隐式地把它bool
    • 哦,这是false ,所以我们不需要评估第二个参数。
    • &&评估的结果作为第一个参数。 (不,不是false ,出于某种原因。)
  • 当dynamic联编程序评估第二个&& ,它执行以下操作:
    • 评估第一个参数。
    • 这是一个T – 隐式地把它bool
    • 哦,这是true ,所以要评估第二个论点。
    • 哦,废话, b没有分配。

简而言之,有一个特殊的“明确赋值”规则,不仅让我们说variables是“明确赋值”还是“未明确赋值”,而且如果是“ false赋值后明确赋值”或“在true陈述后明确分配“。

这些存在于处理&&|| (和!???: :)编译器可以检查variables是否可以在复杂布尔expression式的特定分支中分配。

但是,这些仅在expression式的types保持布尔值时才起作用。 当expression式的一部分是dynamic (或非布尔型的静态types)时,我们不能再可靠地说expression式是true或者是false – 当我们下一次把它转换为bool来决定要采用哪个分支时,它可能已经改变了它心神。


更新:现在已经解决和logging :

以前的编译器为dynamicexpression式实现的明确分配规则允许一些代码的情况,这些代码可能导致读取的variables没有明确分配。 请参阅https://github.com/dotnet/roslyn/issues/4509了解其中的一个报告。;

由于这种可能性,如果val没有初始值,编译器就不能编译这个程序。 以前版本的编译器(在VS2015之前)允许这个程序编译,即使val没有初始值。 现在Roslyn诊断这个尝试读取一个可能未初始化的variables。

这不是一个错误。 请参阅https://github.com/dotnet/roslyn/issues/4509#issuecomment-130872713 ,以获取有关此表单的dynamicexpression式如何使未分配的variables保持不变的示例。