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

來源:互聯網
上載者:User
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,是不是拋異常了呢?自己研究下原因哦。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.