常见的Lambda表达式引起的闭包问题

以下代码的原意是想找出list中满足Name字段包含t, Remark字段包含mark的数据

代码
 
   
// 构造的搜索条件 希望Name包含t remark中包含mark中的文本
Dictionary < string , string > forms = new Dictionary < string , string > ();
forms.Add(
" Name " , " t " );
forms.Add(
" Remark " , " mark " );

// 构造一些数据 理论上全部数据都应该满足上面的那个条件 (忽略大小写)
List < UserInformation > list = new List < UserInformation > () {
new UserInformation(){Name = " Test1 " , Remark = " Remark1 " },
new UserInformation(){Name = " Test2 " , Remark = " Remark2 " },
new UserInformation(){Name = " Test3 " , Remark = " Remark3 " },
};

var lambda
= list.AsQueryable();
foreach ( string key in forms.Keys)
{
string val = forms[key];
if (key == " Name " )
lambda
= lambda.Where(p => p.Name.Contains(val)); // 原意是 在条件是Name的时候 对Name字段做过滤
if (key == " Remark " )
lambda
= lambda.Where(p => p.Remark.Contains(val)); // 原意是 在条件是Remark的时候 对Remark字段做过滤
}

var data
= lambda.ToList(); // 大家可以注意到结果是0条
var data2 = list.AsQueryable().Where(p => p.Name.Contains(forms[ " Name " ])).Where(p => p.Remark.Contains(forms[ " Remark " ])).ToList(); // 这个的结果是3条

 

不过实际情况是data中间一条记录都没有

而hardcode算出来的data2中有3条记录

 

原因如下:

  这个lambda表达式 Where(p=>p.Name.Contains(val))  , 实际上只是保留了一个指向函数外部的val的引用 , 他这个时候并没有把val的真实的值拷贝进来

  真正去读取val值的时候是 lambda.ToList() 这个时候才真正执行lambda表达式取数据,过滤数据 ,也是这个时候才去读取val的值

  而在foreach的第二次操作的时候 val的值被覆盖mark了 那么就造成了 原来的Where(p=>p.Name.Contains(val))  变成了 Where(p=>p.Name.Contains("mark"))  

  注意那个值是mark而不是t

 

  如果我们把三条数据的Name都改成markdafafafadsf 之类的值 那么再次计算data的数据就会变成三条, 大家可以自己弄一下试试,

 

作用域:

  本来val是一个临时变量,他的生命周期应该在foreach结束以后就结束了

  但是 由于他被闭包引用,那么val的生命周期延长到引用对象的生命周期(那个lambda不死....val也就会一直活着)

  

 

 

转载于:https://www.cnblogs.com/PurpleTide/archive/2011/01/07/1929735.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值