• 常见的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也就会一直活着)

      

  • 相关阅读:
    *滚动条cs
    *关于JS动态添加事件
    *JS获取地址栏参数
    *关于Iframe内嵌页面右边总是有空白滚动条的处理
    JAVASCRIPT中使用DOM操作XML文档
    页面间传递变量的方法及使用范围的讨论
    javascript打开模式窗口的用法
    *关于Session*
    *NUnit使用
    Eclipse jQuery plugin spket
  • 原文地址:https://www.cnblogs.com/PurpleTide/p/1929735.html
Copyright © 2020-2023  润新知