lambda表达式,将会带来代码的灵活性,同时使咱们的代码更具表现力。
Dim doubleIt As Func(Of Integer, Integer) = _ Function(x As Integer) x * 2
上面的这个例子,是一个基本lambda表达式定义的示例。它将 doubleIt 定义为接受一个整数并返回一个整数的 lambda 表达式。该 lambda 表达式有效地接受输入,将其乘以 2,而后返回结果。安全
func类型其实是一种将返回类型指定为最后一个泛型参数并容许提供最多四个参数做为前导泛型参数供应的委托(实际有若干 Func 委托,其中每一个委托都接受必定数量的参数)。在 System 命名空间的程序集 System.Core.dll 中定义了 Func 的委托类型。闭包
Dim f0 As Func(Of Boolean) Dim f1 As Func(Of Integer, Boolean)
一个标准的委托应用场景,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表达式。
以前咱们的代码: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签名中定义的变量。
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.
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 sEnd 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