将项目从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使用未分配的局部变量'b'
是什么导致这个问题?是否可以通过编译器设置来修复它?
4 回答
看起来像编译器错误给我 . 至少,确实如此 . 尽管
decimal.TryParse(v, out a)
和decimal.TryParse(v, out b)
表达式是动态计算的,但我希望编译器仍然能够理解,当它到达a <= b
时,a
和b
都是明确分配的 . 即使你可以在动态类型中提出奇怪的想法,我也希望在评估两个TryParse
调用后才能评估a <= b
.然而,事实证明,通过操作符和转换技巧,如果你足够狡猾的话,有一个表达式
A && B && C
来评估A
和C
而不是B
是完全可行的 . 请参阅Roslyn bug report了解Neal Gafter的巧妙例子 .使用
dynamic
工作更加困难 - 当操作数是动态时所涉及的语义更难描述,因为为了执行重载解析,您需要评估操作数以找出涉及的类型,这可能是违反直觉的 . 然而,Neal再次提出了一个示例,该示例显示编译器错误是必需的...这不是一个错误修复 . 为了证明这一点,Neal获得了大量的赞誉 .不,但有其他方法可以避免错误 .
首先,你可以阻止它变得动态 - 如果你知道你只会使用字符串,那么你可以使用
IEnumerable<string>
或给范围变量v
一种string
(即from string v in array
) . 那将是我的首选 .如果你真的需要保持动态,只需给_1151813_一个值开头:
这不会造成任何伤害 - 我们知道实际上你的动态评估仍然会在你使用它之前最终为
b
赋值,使得初始值无关紧要 .此外,似乎添加括号也有效:
这改变了触发各种重载决策的点,并使编译器感到高兴 .
还有一个问题仍然存在 - 需要澄清规范关于使用
&&
运算符进行明确赋值的规则,以声明它们仅在&&
运算符在其"regular"实现中使用两个bool
操作数时才适用 . 我将尝试确保这是针对下一个ECMA标准修复的 .这似乎是Roslyn编译器中的错误,或者至少是回归 . 已提交以下错误以跟踪它:
在此期间,Jon的excellent answer有几个工作 .
由于我在错误报告中受过如此刻苦的教育,我将尝试自己解释一下 .
想象一下
T
是一些用户定义的类型,隐式转换为bool
,在false
和true
之间交替,从false
开始 . 就编译器所知,第一个&&
的第一个参数可能会评估为该类型,因此它必须是悲观的 .如果,那么,它让代码编译,这可能发生:
当动态 Binders 评估第一个
&&
时,它执行以下操作:评估第一个参数
这是一个
T
- 隐式地将其强制转换为bool
.哦,这是
false
,所以我们不需要评估第二个参数 .将
&&
evaluate的结果作为第一个参数 . (不,不是false
,出于某种原因 . )当动态 Binders 评估第二个
&&
时,它执行以下操作:评估第一个参数 .
这是一个
T
- 隐含地将其强制转换为bool
.哦,这是
true
,所以评估第二个参数 ....哦废话,
b
未分配 .在规范方面,简而言之,有一些特殊的规则让我们不仅可以说变量是"definitely assigned"还是"not definitely assigned",而且还可以说“在
true
语句之后false
语句" or "之后明确赋值” .这些存在,以便在处理
&&
和||
(和!
)时和??
和?:
)编译器可以检查是否可以在复杂布尔表达式的特定分支中分配变量 .但是,这些只在表达式的类型保持布尔值时才起作用 . 当表达式的一部分是
dynamic
(或非布尔静态类型)时,我们再也无法可靠地说表达式是true
或false
- 下次我们将它转换为bool
以决定采取哪个分支时,它可能已经改变了它心神 .更新:现在已经resolved和documented:
这不是一个错误 . 有关此表单的动态表达式如何使这样的out变量未分配的示例,请参见https://github.com/dotnet/roslyn/issues/4509#issuecomment-130872713 .