在我将我的项目从 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();
}
编译器返回错误:
Error CS0165 Use of unassigned local variable 'b'
导致此问题的原因是什么?是否可以通过编译器设置修复它?
最佳答案
What does cause this issue?
在我看来像是一个编译器错误。至少,它做到了。虽然decimal.TryParse(v, out a)
和 decimal.TryParse(v, out b)
表达式是动态求值的,我期望编译器在它到达 a <= b
时仍能理解这一点, 两者 a
和 b
肯定被分配了。即使你在动态类型中可能会遇到一些奇怪的事情,我也希望只评估 a <= b
在评估了 TryParse
之后电话。
然而,事实证明,通过运算符和转换技巧,表达式A && B && C
是完全可行的。评估A
和 C
但不是 B
- 如果你足够狡猾。查看Roslyn bug report Neal Gafter 的巧妙示例。
让它与 dynamic
一起工作更难 - 操作数是动态的时涉及的语义更难描述,因为为了执行重载决议,您需要评估操作数以找出涉及的类型,这可能是违反直觉的。然而,Neal 再次提出了一个示例,表明编译器错误是必需的……这不是一个错误,而是一个错误修复。 Neal 证明了这一点,获得了巨大的荣誉。
Is it possible to fix it through compiler settings?
不,但是有其他方法可以避免错误。
首先,您可以阻止它成为动态的 - 如果您知道您只会使用字符串,那么您可以使用 IEnumerable<string>
或给出范围变量v
一种 string
(即 from string v in array
)。那将是我的首选。
如果您真的需要保持动态,只需提供 b
开始的值:
decimal a, b = 0m;
这不会造成任何伤害 - 我们知道实际上您的动态评估不会做任何疯狂的事情,所以您最终仍会为 b
赋值。在你使用它之前,让初始值变得无关紧要。
此外,添加括号似乎也有效:
where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)
这改变了触发各种重载决议的点,并且恰好让编译器高兴。
一个问题仍然存在 - 规范关于 &&
明确赋值的规则运营商需要澄清声明他们只适用于 &&
运算符在其“常规”实现中使用两个 bool
操作数。我会努力确保在下一个 ECMA 标准中解决这个问题。
关于c# - Roslyn 编译代码失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31961411/