为了账号安全,请及时绑定邮箱和手机立即绑定

C#在预见中重用变量有什么原因吗?

C#在预见中重用变量有什么原因吗?

慕桂英3389331 2019-06-09 15:42:14
C#在预见中重用变量有什么原因吗?在C#中使用lambda表达式或匿名方法时,我们必须警惕访问修改后的闭包陷阱。例如:foreach (var s in strings){    query = query.Where(i => i.Prop == s); // access to modified closure    ...}由于修改了闭包,上述代码将导致所有Where的最后一个值为基础的查询中的子句。s.如所解释这里,这是因为s中声明的变量foreach上面的循环在编译器中是这样翻译的:string s;while (enumerator.MoveNext()){    s = enumerator.Current;    ...}而不是这样:while (enumerator.MoveNext()){    string s;    s = enumerator.Current;    ...}如前所述这里,在循环之外声明变量没有任何性能优势,在正常情况下,我能想到这样做的唯一原因是如果您计划在循环范围之外使用该变量:string s;while (enumerator.MoveNext()){    s = enumerator.Current;    ...}var finalString = s;中定义的变量。foreach循环不能在循环之外使用:foreach(string s in strings){}var finalString = s; // won't work: you're outside the scope.因此,编译器声明变量的方式使它非常容易出错,而错误通常很难找到和调试,同时也不会产生任何可感知的好处。你有什么可以用的吗?foreach循环是这样的,如果它们是用内部作用域变量编译的,或者这只是在匿名方法和lambda表达式可用或通用之前所做的任意选择,而且从那时起就没有修改过?
查看完整描述

3 回答

?
婷婷同学_

TA贡献1844条经验 获得超8个赞

你要问的是埃里克·利珀特在他的博客文章中详细介绍了他的问题。关闭被认为有害的循环变量还有它的续集。

对我来说,最有说服力的论点是,在每次迭代中使用新变量将不符合for(;;)样式循环。你想要一个新的int i在每一次迭代中for (int i = 0; i < 10; i++)?

这种行为最常见的问题是对迭代变量进行闭包,并且有一个简单的解决方法:

foreach (var s in strings){
    var s_for_closure = s;
    query = query.Where(i => i.Prop == s_for_closure); // access to modified closure

我在博客上发表了关于这个问题的文章:C#中Foreach变量的闭包.


查看完整回答
反对 回复 2019-06-09
?
跃然一笑

TA贡献1826条经验 获得超6个赞

被这样咬过之后,我习惯于将本地定义的变量包含在最内部的范围中,用于转移到任何闭包。在你的例子中:

foreach (var s in strings){
    query = query.Where(i => i.Prop == s); // access to modified closure

我知道:

foreach (var s in strings){
    string search = s;
    query = query.Where(i => i.Prop == search); // New definition ensures unique per iteration.

一旦你有了这个习惯,你就可以在非常罕见的情况,您实际上打算绑定到外部作用域。老实说,我从来没有这样做过。


查看完整回答
反对 回复 2019-06-09
  • 3 回答
  • 0 关注
  • 386 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信