ram*_*l89 95 .net c# linq 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();
}
Run Code Online (Sandbox Code Playgroud)
编译器返回错误:
错误CS0165使用未分配的局部变量'b'
是什么导致这个问题?是否可以通过编译器设置来修复它?
Jon*_*eet 112
是什么导致了这个问题?
看起来像编译器错误给我.至少,确实如此.虽然decimal.TryParse(v, out a)和decimal.TryParse(v, out b)表现进行动态评估,我希望编译器还了解到,通过它到达的时间a <= b,无论是a和b肯定分配.即使你可以在动态类型中提出奇怪的想法,我也希望a <= b在评估两个TryParse调用后才能进行评估.
然而,事实证明,通过操作符和转换变得棘手,有一个表达式A && B && C可以评估A,C但不是B- 如果你足够狡猾的话.有关Neal Gafter巧妙的例子,请参阅Roslyn错误报告.
使用dynamic它更加困难 - 当操作数是动态时所涉及的语义更难描述,因为为了执行重载解析,您需要评估操作数以找出涉及的类型,这可能是违反直觉的.然而,Neal再次提出了一个示例,该示例显示编译器错误是必需的...这不是错误,它是一个错误修复.为了证明这一点,Neal获得了大量的赞誉.
是否可以通过编译器设置来修复它?
不,但有其他方法可以避免错误.
首先,你可以阻止它变得动态 - 如果你知道你只会使用字符串,那么你可以使用IEnumerable<string> 或给范围变量v一种类型string(即from string v in array).那将是我的首选.
如果你真的需要保持动态,只需给出b一个值:
decimal a, b = 0m;
Run Code Online (Sandbox Code Playgroud)
这不会造成任何伤害 - 我们知道实际上您的动态评估不会做任何疯狂的事情,因此您b在使用它之前仍然会最终分配值,从而使初始值无关紧要.
此外,似乎添加括号也有效:
where decimal.TryParse(v, out a) && (decimal.TryParse("15", out b) && a <= b)
Run Code Online (Sandbox Code Playgroud)
这改变了触发各种重载决策的点,并使编译器感到高兴.
还有一个问题仍然存在 - 规范与&&运营商明确分配的规则需要明确说明它们仅在&&运营商在其"常规"实施中使用两个bool操作数时才适用.我将尝试确保这是针对下一个ECMA标准修复的.
Raw*_*ing 16
由于我在错误报告中受过如此刻苦的教育,我将尝试自己解释一下.
想象一下T是一些用户定义的类型,带有隐式强制转换bool,在它之间交替,false并从中true开始false.就编译器所知,第dynamic一个参数&&可能会评估为该类型,因此它必须是悲观的.
如果,那么,它让代码编译,这可能发生:
&&,它执行以下操作:
T- 隐含地投入其中bool.false,所以我们不需要评估第二个参数.&&evaluate 的结果作为第一个参数.(不,不是false,出于某种原因.)&&,它执行以下操作:
T- 隐含地投入其中bool.true,所以评估第二个论点.b没有分配.简而言之,有一些特殊的"明确赋值"规则,它们不仅可以说明变量是"明确赋值"还是"未明确赋值",而且还可以false说明" 它是在声明后明确赋值"还是"绝对赋值"在true声明后分配".
这些存在使得与处理时&&和||(和!和??和?:)编译器可以检查是否变量可以在复杂的布尔表达式的特定分支被分配.
但是,这些只在表达式的类型保持布尔值时才起作用.当表达式的一部分是dynamic(或非布尔静态类型)时,我们再也无法可靠地说表达式是- true或者false- 下次我们将其转换bool为决定采用哪个分支时,它可能已经改变了主意.
先前编译器为动态表达式实现的明确赋值规则允许某些代码可能导致读取的变量未明确赋值.有关此问题的报告,请参阅https://github.com/dotnet/roslyn/issues/4509.
...
由于这种可能性,如果val没有初始值,编译器不得允许编译该程序.先前版本的编译器(在VS2015之前)允许该程序编译,即使val没有初始值.罗斯林现在诊断这种尝试读取可能未初始化的变量.
Nea*_*ter 15
这不是一个错误.有关此表单的动态表达式如何使这样的out变量未分配的示例,请参阅https://github.com/dotnet/roslyn/issues/4509#issuecomment-130872713.