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 <= b
, a
和b
都是肯定的分配。 即使是在dynamicinput中也可能出现的奇怪现象,我只希望在对两个TryParse
调用进行评估之后评估a <= b
。
然而,事实certificate,通过操作和转换的棘手,有一个expression式A && B && C
评估A
和C
而不是B
– 完全可行 – 如果你足够狡猾。 看看Neal Gafter的巧妙例子的Roslyn错误报告 。
使用dynamic
工作更加困难 – 当操作数是dynamic的时候涉及到的语义很难描述,因为为了执行重载parsing,您需要评估操作数以找出涉及哪些types,这可能是违反直觉的。 然而,Neal再次提出了一个例子,它显示了编译器错误是必需的…这不是一个错误,这是一个错误修复 。 巨大的赞誉Nealcertificate了它。
是否有可能通过编译器设置来解决它?
不,但也有避免错误的select。
首先,你可以阻止它的dynamic – 如果你知道你只会使用string,那么你可以使用IEnumerable<string>
或给范围variablesv
的string
types(即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是一个回归。 以下错误已被提交以追踪它:
与此同时,乔恩的优秀答案有几个解决方法。
由于我在错误报告中受过很严格的训练,所以我会试着自己解释一下。
想象一下, T
是一些用户定义的types,隐式转换为bool
,在false
和true
之间交替,从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保持不变的示例。