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代码生成的实质

之前我们的代码:

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
原文地址:https://www.cnblogs.com/RealAlex/p/3178581.html