C# 7中不允许在查询子句中使用Out变量和模式变量声明

3

为什么查询子句中不允许使用out变量?

如果我在这里使用out变量,它会失败:

string json = "{'PayDays':['2017-07-07','2017-07-21','2017-08-04','2017-08-18']}";
var pd = JsonConvert.DeserializeObject<Accounting>(json);

var rm = from item in pd.PayDays
     where (DateTime.TryParse(item, out DateTime dateresult)) ?
    dateresult.Subtract(DateTime.Now).Days >= 0 ? true : false : false      
    select item;
rm.Dump();

但是旧的方式也可以工作:
DateTime result;
var rm = from item in pd.PayDays
         where DateTime.TryParse(item, out result) ? (result.Subtract(DateTime.Now).Days >= 0 ? true : false) : false
         select item;
rm.Dump();
2个回答

8

这里是相关的LDM笔记

结论:

我们没有时间在C# 7.0中完成这个功能。如果我们想留给自己未来的空间,我们需要确保我们不允许查询子句中的表达式变量今天意味着其他东西,这将与未来矛盾。
当前语义是查询子句中的表达式变量仅限于该查询子句的范围。这意味着两个后续查询子句可以在表达式变量中使用相同的名称,例如。这与允许这些变量跨查询子句边界共享作用域的未来不一致。
因此,如果我们想在未来允许这样做,我们必须在C# 7.0中加入一些限制以保护设计空间。我们有几个选择:
- 在查询子句中完全禁止表达式变量 - 要求给定查询表达式中的所有表达式变量具有不同的名称
前者是一个大锤,但后者需要很多工作才能正确执行,并且似乎有风险无法完全阻止所有问题。
我们在C# 7.0中不会使用表达式变量或解构,但希望在未来使用它们。为了保护我们实现这一目标的能力,即使这是一个很大的限制,我们将完全禁止在查询子句中使用表达式变量。

0
问题在于你展示的翻译对于普通的LINQ to objects可以正常工作,但是对于其他提供程序(如PLINQ或Entity Framework)可能会有问题。
例如,考虑你为查询提出的翻译修改为使用PLINQ:
DateTime result;
var rm = from item in pd.PayDays.AsParallel()
         where DateTime.TryParse(item, out result) ? (result.Subtract(DateTime.Now).Days >= 0 ? true : false) : false
         select item;
var list = rm.ToList();

这段代码不是线程安全的,因为多个线程共享一个单一的result变量,并且它们很可能会在同一时间尝试使用它,导致结果不正确。

有方法可以正确地转换这种查询,至少在某些情况下可以,但它们并不简单,所以在LINQ查询语法中不允许out变量。虽然未来版本的C#中可能会允许它们


从语言角度来看,翻译似乎相当简单:等价于 from item in pd.PayDays.AsParallel() let resultHolder = new DisplayClass() where DateTime.TryParse(item, out resultHolder.result) ? ... : ... select item;,使用与已经为其他原因生成的相同类型的 DisplayClass 类。您能否举一个这种简单方法不起作用或表现出意外行为的例子? - user743382

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接