VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • C#3.0入门系列(十二)-Lambda表达式中Lifting

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  Lambda表达式是由匿名方法演化而来的更加高级的形式。关于匿名方法,请参阅http://msdn.microsoft.com/msdnmag/issues/04/05/C20/。关于Lambda表达式的演化,请参阅http://msdn.microsoft.com/msdnmag/issues/07/06/csharp30/default.aspx?loc=zh。英文原版为http://msdn.microsoft.com/msdnmag/issues/07/06/CSharp30/。

  1,Lambda表达式中的lifting

  在c# 2.0中,匿名方法的使用,是这样的。

class SomeClass
{
  delegate void SomeDelegate();
  public void InvokeMethod()
  {
   SomeDelegate del = delegate()
             {
               MessageBox.Show("Hello");
             };
   del(); 
  }
}

  在LINQ 的演变及其对 C# 设计的影响 一文中,其断言如果 lambda 表达式首先被引入语言,那么就不会有对匿名方法的需要了。在本系列前面的一些文章中,也曾提到lambda 表达式,但并没有做太深入的引述。本文所要讲的是Lambda表达式中lifting,将开始和大家体会lambda表达式的一些细节。

  编译下面的小程序,看看输出结果,是不是大吃一惊

using System;
using System.Collections.Generic;
using System.Linq;
  
namespace Tester
{
  class Program
  {
    static void Main(string[] args)
    {
      List<Func<int>> list = new List<Func<int>>();
  
      for (int i = 0; i < 3; i++)
      {
        list.Add(() => i);
      }
  
      foreach (var item in list)
      {
        Console.WriteLine(item());
      }
    }
  }
}

 

  我们定义了一个list,其存储格式为func<int>,即返回int型的代理。而后,用for循环,将 i 封装进lambda表达式,并加入到该list中。而后,用foreach循环输出结果。因为lambda表达式,其实质就是个代理,也就指向一个匿名函数,所以,使用item()来调用它,让所指向的函数执行。

  问题是,你所盼望输出,0,1,2,而实际结果均是3。为什么会这样呢?这牵扯到两个原因。

  第一,在for循环中,只能有一个 i 变量。即再第一次循环时,i 的地址就分配好了,不会因为循环次数的多少而发生任何改变,其改变的只能是里面装载的值。

  第二,lambda表达式在构造时, 传进去的是变量的地址,而不是具体值。只有当真正执行这个lambda表达式时,才会去确定它的值。这就是为什么上面的例子中,其结果均为3。(for循环在最后,又给 i 加了1)

  我们可以很容易,就将起解决掉。在for循环中,定义一临时变量,存储 i 的值即可。因为编译器会对该临时变量重新分配内存,这样,每次循环,都重新分配新的内存,就不会有这个问题了。再来运行下面的这个例子。

using System;
using System.Collections.Generic;
using System.Linq;
  
namespace EnterpriseTester
{
  class Program
  {
    static void Main(string[] args)
    {
      List<Func<int>> list = new List<Func<int>>();
  
      for (int i = 0; i < 3; i++)
      {
        int temp = i;
        list.Add(() => temp);
      }
  
      foreach (var item in list)
      {
        Console.WriteLine(item());
      }
    }
  }
}

 

  是不是满足了你的要求了呢?这个temp,就称为lifting。lift是美语中的电梯,翻译为梯子或垫脚石,比较妥帖。

  2,lifting在Linq To Sql中的影响。

  Lambda表达式在Linq To Sql中大量应用,这个问题势必要影响到其sql语句的形成。看下面的例子

     string[] keyWords = string[] keyWords = new string[] { "111", "222", "333", "444" };
      SomeDataContext ctx = new SomeDataContext ();
      var entitys = from e in ctx.Entity
              select e;
      foreach (string keyWord in keyWords)
      {
        entitys = entitys.Where(e => e.Text.Contains(keyWord));
      }
        var q = entitys.ToList();

  本意是想查找,全部满足模糊匹配的所有记录,其实际生成的sql语句中,只传入了“%444%”。加个lifting吧,问题就解决了。

  大家可以用for循环替换foreach循环,如果,不加lifting,是不是抛异常了呢?自己研究下原因哦。

 

 

  我们定义了一个list,其存储格式为func<int>,即返回int型的代理。而后,用for循环,将 i 封装进lambda表达式,并加入到该list中。而后,用foreach循环输出结果。因为lambda表达式,其实质就是个代理,也就指向一个匿名函数,所以,使用item()来调用它,让所指向的函数执行。

  问题是,你所盼望输出,0,1,2,而实际结果均是3。为什么会这样呢?这牵扯到两个原因。

  第一,在for循环中,只能有一个 i 变量。即再第一次循环时,i 的地址就分配好了,不会因为循环次数的多少而发生任何改变,其改变的只能是里面装载的值。

  第二,lambda表达式在构造时, 传进去的是变量的地址,而不是具体值。只有当真正执行这个lambda表达式时,才会去确定它的值。这就是为什么上面的例子中,其结果均为3。(for循环在最后,又给 i 加了1)

  我们可以很容易,就将起解决掉。在for循环中,定义一临时变量,存储 i 的值即可。因为编译器会对该临时变量重新分配内存,这样,每次循环,都重新分配新的内存,就不会有这个问题了。再来运行下面的这个例子。

using System;
using System.Collections.Generic;
using System.Linq;
  
namespace EnterpriseTester
{
  class Program
  {
    static void Main(string[] args)
    {
      List<Func<int>> list = new List<Func<int>>();
  
      for (int i = 0; i < 3; i++)
      {
        int temp = i;
        list.Add(() => temp);
      }
  
      foreach (var item in list)
      {
        Console.WriteLine(item());
      }
    }
  }
}

 

  是不是满足了你的要求了呢?这个temp,就称为lifting。lift是美语中的电梯,翻译为梯子或垫脚石,比较妥帖。

  2,lifting在Linq To Sql中的影响。

  Lambda表达式在Linq To Sql中大量应用,这个问题势必要影响到其sql语句的形成。看下面的例子

     string[] keyWords = string[] keyWords = new string[] { "111", "222", "333", "444" };
      SomeDataContext ctx = new SomeDataContext ();
      var entitys = from e in ctx.Entity
              select e;
      foreach (string keyWord in keyWords)
      {
        entitys = entitys.Where(e => e.Text.Contains(keyWord));
      }
        var q = entitys.ToList();

  本意是想查找,全部满足模糊匹配的所有记录,其实际生成的sql语句中,只传入了“%444%”。加个lifting吧,问题就解决了。

  大家可以用for循环替换foreach循环,如果,不加lifting,是不是抛异常了呢?自己研究下原因哦。

 



相关教程