程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C# 3.0入門系列(十二)-Lambda表達式中Lifting

C# 3.0入門系列(十二)-Lambda表達式中Lifting

編輯:關於C#

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,是不是拋異常了呢?自己研究下原因哦。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved