Lambda 筆記

lambda表達式,將會帶來代碼的靈活性,同時使咱們的代碼更具表現力。
     
   Dim doubleIt As Func(Of Integer, Integer) = _
            Function(x As Integer) x * 2

上面的這個例子,是一個基本lambda表達式定義的示例。它將 doubleIt 定義爲接受一個整數並返回一個整數的 lambda 表達式。該 lambda 表達式有效地接受輸入,將其乘以 2,而後返回結果。安全

Func類型

func類型其實是一種將返回類型指定爲最後一個泛型參數並容許提供最多四個參數做爲前導泛型參數供應的委託(實際有若干 Func 委託,其中每一個委託都接受必定數量的參數)。在 System 命名空間的程序集 System.Core.dll 中定義了 Func 的委託類型。閉包

        Dim f0 As Func(Of Boolean)
        Dim f1 As Func(Of Integer, Boolean)

Lambda表達是做爲回調

一個標準的委託應用場景,processList方法遍歷列表中的每一個元素,檢查是否須要處理該項,而後進行一些處理。函數

Public Delegate Function ShouldProcess(Of T)(element As T) As Boolean
 
    Sub ProcessList(Of T)( _
                elements As List(Of T), shouldProcess As ShouldProcess(Of T))

        For Each elem In elements
            If shouldProcess(elem) Then
                'do some processing here
            End If
        Next
    End Sub
在沒有使用lambda之類的使用辦法:
Public Class Person
    Public Age As Integer
End Class
 
 Function _PrivateShouldProcess(person As Person) As Boolean
        Return person.Age > 50
 End Function
 
 Sub DoIt()
        Dim list As New List(Of Person)
        ProcessList(list, AddressOf _PrivateShouldProcess)
 End Sub
有了lambda以後的寫法:
 Sub DoItAgain()
     Dim list As New List(Of Person)
     ProcessList(list, Function(person As Person) person.Age > 50)
 End Sub
有了lambda表達式後,不須要建立你本身打函數來執行處理邏輯。只有在須要使用的地方纔定義委託。
lambda表達式具備強大功能和便攜性,而且使你的代碼更便於閱讀和維護。好比,類型推斷。
 

類型推斷

  'lambda 類型推斷 
   Dim lambda As Func(Of Integer, Integer) = Function(x) x * x
示例中,lambda變量的類型被定爲func(of integer,integer)。這是一個接受一個整型參數,並返回一個整數參數的委託。所以,編譯器自動推斷lambda參數x是整數,且lambda的返回值是整數。
 
在調用接受委託的方法是,你一樣會享受到lambda表達式參數推斷帶來的益處。咱們能夠將上文中的DoItAggin()從新定義:
    Sub DoItAgain()
        Dim list As New List(Of Person)
        ProcessList(list, Function(person) person.Age > 50)
    End Sub
推斷結果,若是沒有定義委託類型,並想讓編譯器合成一個,這種狀況至關簡單。
   Dim lambda1 = Function(x As Integer) x * x
示例中,lambda表達式是徹底類型(lambda參數x是整數類型,編譯器推斷出返回值是整數,由於整數×整數= 整數)。然而lambda1變量沒有類型。所以,編譯器會合成一個與lambda表達式形狀相匹配的匿名委託,而後將該委託類型分配給lambda1。這意味着,可以動態建立lambda表達式而無需靜態構造他們的委託類型。
場景1:
描述:面臨這樣一種狀況,你須要一個對一組變量進行檢查的條件判斷邏輯,而且這個條件判斷邏輯會被使用到若干地方。
Public Class Motorcycle

    Public Property Color() As String
    Public Property Cc() As Integer
    Public Property Weight() As Integer
End Class

Public Class TestRun

    Public Sub PrintReport(motorcycle As Motorcycle)

        If motorcycle.Color = "Red" And motorcycle.Cc = 60 And _
            motorcycle.Weight > 300 And motorcycle.Weight < 400 Then

            'do something here 
        End If
        'do something here
        If motorcycle.Color = "Red" And motorcycle.Cc = 60 And _
            motorcycle.Weight > 300 And motorcycle.Weight < 400 Then

            'do something here 
        End If

    End Sub
極可能,最容易想到的是將判斷邏輯提取到方法中,而後進行復用。可是咱們此處的條件判斷邏輯有在這一個函數中使用,而其餘地方都用不到。不建議以上作法。這樣,咱們的類被僅用於支持此函數的幫助函數(即,提取出的條件判讀函數)弄亂。這樣作會對可維護性形成負面影響,例如,別人調用了這個幫助函數,而我須要修改呢?
改進後的作法:
    Public Sub PrintAgain(motorcycle As Motorcycle)
        Dim check = Function(m As Motorcycle) m.Color = "Red" And _
                        m.Cc = 60 And m.Weight > 300 And m.Weight < 400
        If check(motorcycle) Then
            'do something
        End If
        'do something
        If check(motorcycle) Then
            'do something
        End If

    End Sub
咱們已經將條件判斷邏輯提取處理,以便檢查motorcycle類中的一些條件。而不是將這些邏輯放入到一個隱蔽的私有方法中。經過lambda表達式,讓編譯器自動建立委託類型,並與全部必需的工做聯繫起來。這樣能夠像調用方法同樣調用lambda表達式。

Lambda代碼生成的實質

以前咱們的代碼:spa

Sub TestLambda()
    Dim doubleIt As Func(Of Integer, Integer) = _
        Function(x As Integer) x * 2
    Console.WriteLine(doubleIt(10))
End Sub
咱們知道func是一個委託,而委託是一個函數指針,那麼編譯器是如何發揮功能的?在此例中,編譯器爲你生成了新的函數,並設置委託,使其指向新的函數:
Function $GeneratedFunction$(x As Integer) As Integer
    Return x * 2
End Sub

Sub TestLambda()
    Dim doubleIt As Func(Of Integer, Integer) = _
        AddressOf $GeneratedFunction$
    Console.WriteLine(doubleIt(10))
End Sub
編譯器實質上接受 lambda 表達式,並根據它的內容建立新的函數,而後改變賦值語句,因此 lambda 表達式將採用所生成函數的地址。在這種狀況下,該函數在含有使用 lambda 表達式的方法的相同父項中生成。若是 TestLambda 在類 C 上定義,那麼生成的函數將在 C 上定義。請注意,生成的函數是不可調用的,且標記爲私有。

Lambda表達變量--閉包

前面的示例中,lambda表達式中的參數是經過參數進行傳遞的(綁定變量)。
在數學中,lambda計算中的基本概念是,擁有自由變量或綁定變量。
自由變量,是指那些定義在方法中的局部變量或者參數。
綁定變量,是指那些在lambda簽名中定義的變量。
     Dim y As Integer = 10
     Dim addTen As Func(Of Integer, Integer) = Function(x) x + y
在上面的代碼中,x 由於是lambda表達式的形參,因此被認定爲lambda中的一個綁定變量;而y 由於屬於lambda表達式所在函數的局部變量,因此被認定爲自由變量。
在定義了lambda表達式以後,它被看做是一個委託類型。看下面的例子:
    Function MakeLambda() As Func(Of Integer, Integer)
        Dim y = 10
        Dim addTen As Func(Of Integer, Integer) = Function(x) x + y
        Return addTen
    End Function

    Sub Uselambda()
        Dim addTen = MakeLambda()
        Console.WriteLine(addTen(5))
    End Sub
執行上面的代碼,你會發現控制檯輸出的是15.你可能會想,這是如何實現的,函數Makelambda將y定義爲局部變量,並且lambda正在使用y,但lambda是從函數makelambda返回的。函數UseLambda從Makelambda中獲得lambda並執行,這看起來有些像是,變量y被記住了。
y的生存週期是makeLambda的方法。當咱們執行從makelambda返回的lambda時,makelambda會超出範圍,且應清除它的堆棧空間。可是y在堆棧上定義的,此時它會與lambda粘滯。
這種粘滯就是奇妙所在,一般稱爲變量提高。在這種狀況下,變量y稱爲提高變量。而且,如你所見,提高變量很強大,編譯器爲你作了不少輔助工做,以得到變量的狀態,並在它們的正常生產期以外繼續保留它們。
更正式地說,當編譯器遇到含有自由變量的lambda表達式時,它會把自由變量提高爲閉包的類。閉包的生存週期超出了在其中承載的自由變量的生存週期。 
正如前面所分析的,x與lambda的參數綁定,而y是自由變量。編譯器探測到這些,並繼續建立一個捕獲自由變量以及爲lambda表達式定義實現一個閉包類。
Public Class _Closure$__1
    Public y As Integer
    Public Function _Lambda$__1(ByVal x As Integer) As Integer
        Return x + Me.y
    End Function
End Class
再看下面的示例:
    Sub TestLambda()
        Dim y = 10
        Dim lambda = Function(x As Integer) x + y
        y = 20
        Console.WriteLine(lambda(5))
    End Sub
 顯示的結果應該是25,在lambda執行之際,y的值變爲20,所以當lambda執行以後,它返回20+5.

充分利通lambda表達式

if運算符:
     Dim conditionCheck = Function(x1 As Integer, y As Integer) x1 > y
     Dim x = If(conditionCheck(10, 20), 10, 20)
 if關鍵字與iif函數調用相似,惟一不一樣的是if關鍵是類型安全的。這意味着上面的例子中,編譯器會推斷if關鍵字的兩個分支返回一個整數,所以,它能夠推斷出x的類型是integer
lambda表達式中,使用if關鍵字
     Dim x = Function(c As Customer) _
                 If(c.CustomerId = 4, c.FirstName, c.LastName)
 
 
 
 參考:http://msdn.microsoft.com/zh-cn/magazine/cc163362.aspx

 

 

追加:vb中在lambda表達式中,寫多句表達式指針

     Dim f1 = Function(s)
                  Console.WriteLine(s)
                  Return s
               End Function

     Dim f1T As Func(Of String, String) = _
            Function(s)
                Console.WriteLine(s)
                Return s
            End Function

 

        Dim colr1 = Sub(strValue As String, intA As Integer, intB As Integer)
                        Dim asda As New Motorcycle()
                        asda.Cc = strValue
                        asda.Color = intA
                        asda.Weight = intB
                    End Sub
相關文章
相關標籤/搜索