共用方式為


Lambda 運算式

更新:2007 年 11 月

「Lambda 運算式」(Lambda Expression) 是沒有名稱的函式,會計算並傳回單一值。委派型別 (Delegate Type) 有效時,即可使用 Lambda 運算式。

注意事項:

RemoveHandler 陳述式 (Statement) 是例外狀況 (Exception)。您無法針對 RemoveHandler 的委派參數傳遞 Lambda 運算式。

下列範例是會遞增其引數並傳回值的 Lambda 運算式。

Function (num As Integer) num + 1

因為 Lambda 運算式是運算式,所以只能做為陳述式的一部分。

例如,特別是在要多次使用函式的情況下,您可能會將函式指派至變數名稱。

Dim add1 = Function(num As Integer) num + 1

若要呼叫函式,請傳送參數的值。

' The following line prints 6.
Console.WriteLine(add1(5))

或者,您可以同時宣告並執行函式。

Console.WriteLine((Function(num As Integer) num + 1)(5))

Lambda 運算式可以傳回做為函式呼叫 (Function Call) 的值 (請見本主題稍後「內容」章節中的範例),或傳遞做為委派參數的引數。在下列範例中,布林 (Boolean) Lambda 運算式會做為引數傳遞至方法 testResult。這個方法會將布林測試套用至整數引數 value,而且當套用至 value 時,如果 Lambda 運算式傳回 True,則顯示「成功」(Success),如果 Lambda 運算式傳回 False,則顯示「失敗」(Failure)。

Module Module2

    Sub Main()
        ' The following line will print Success, because 4 is even.
        testResult(4, Function(num) num Mod 2 = 0)
        ' The following line will print Failure, because 5 is not > 10.
        testResult(5, Function(num) num > 10)
    End Sub

    ' Sub testResult takes two arguments, an integer value and a 
    ' Boolean function. 
    ' If the function returns True for the integer argument, Success
    ' is displayed.
    ' If the function returns False for the integer argument, Failure
    ' is displayed.
    Sub testResult(ByVal value As Integer, ByVal fun As Func(Of Integer, Boolean))
        If fun(value) Then
            Console.WriteLine("Success")
        Else
            Console.WriteLine("Failure")
        End If
    End Sub

End Module

查詢中的 Lambda 運算式

在 Language-Integrated Query (LINQ) 中,Lambda 運算式是許多標準查詢運算子的基礎。編譯器 (Compiler) 會建立 Lambda 運算式以擷取基本查詢方法 (例如 Where、Select、Order By、Take While 等等) 中定義的計算。

例如,以下列查詢為例:

Dim londonCusts = From cust In db.Customers 
                  Where cust.City = "London" 
                  Select cust

這個範例會編譯成下列程式碼:

Dim londonCusts = db.Customers _
    .Where(Function(cust) cust.City = "London") _
    .Select(Function(cust) cust)

如需查詢方法的詳細資訊,請參閱查詢 (Visual Basic)

Lambda 運算式語法

Lambda 運算式的語法類似標準函式。其差異如下:

  • Lambda 運算式沒有名稱。

  • Lambda 運算式不能有修飾詞 (Modifier),例如 Overloads 或 Overrides。

  • Lambda 運算式不會使用 As 子句指定函式的傳回型別。而是從 Lambda 運算式評估之主體的值來推斷型別。例如,如果 Lambda 運算式的主體是 Where cust.City = "London",其傳回型別為 Boolean。

  • 函式的主體必須是運算式,而不是陳述式。主體可以由對函式程序的呼叫組成,但不可由對子程序的呼叫組成。

  • 沒有 Return 陳述式。函式傳回的值就是函式主體中運算式的值。

  • 沒有 End Function 陳述式。

  • 所有參數都必須具有指定的資料型別,不然所有參數就都必須經過推斷。

  • 不允許使用 Optional 和 Paramarray 參數。

  • 不允許使用泛型參數。

因為這些限制以及 Lambda 運算式的使用方式,所產生的結果通常都是簡短不複雜的。

內容

任一 Lambda 運算式定義於某個方法中時,該運算式會將本身的內容與該方法共用。它的存取權限與包含方法中撰寫的任何程式碼相同。這包括對包含方法中成員變數、函式和子函式、Me 及參數和本機變數的存取權。

對於包含方法中的本機變數和參數的存取權期,可以延伸超過該方法的存留期 (Lifetime)。只要委派 (Delegate) 參考無法進行記憶體回收的 Lambda 運算式,就會保留對於原始環境中變數的存取權。在下列範例中,變數 target 是 makeTheGame 的本機變數,而後者是 Lambda 運算式 playTheGame 在其中定義的方法。請注意,在 Main 中指派給 takeAGuess 的傳回 Lambda 運算式,仍然可以存取本機變數 target。

Module Module1

    Sub Main()
        ' Variable takeAGuess is a Boolean function. It stores the target
        ' number that is set in makeTheGame.
        Dim takeAGuess As gameDelegate = makeTheGame()

        ' Set up the loop to play the game.
        Dim guess As Integer
        Dim gameOver = False
        While Not gameOver
            guess = CInt(InputBox("Enter a number between 1 and 10 (0 to quit)", "Guessing Game", "0"))
            ' A guess of 0 means you want to give up.
            If guess = 0 Then
                gameOver = True
            Else
                ' Tests your guess and announces whether you are correct. Method takeAGuess
                ' is called multiple times with different guesses. The target value is not 
                ' accessible from Main and is not passed in.
                gameOver = takeAGuess(guess)
                Console.WriteLine("Guess of " & guess & " is " & gameOver)
            End If
        End While

    End Sub

    Delegate Function gameDelegate(ByVal aGuess As Integer) As Boolean

    Public Function makeTheGame() As gameDelegate

        ' Generate the target number, between 1 and 10. Notice that 
        ' target is a local variable. After you return from makeTheGame,
        ' it is not directly accessible.
        Randomize()
        Dim target As Integer = CInt(Int(10 * Rnd() + 1))

        ' Print the answer if you want to be sure the game is not cheating
        ' by changing the target at each guess.
        Console.WriteLine("(Peeking at the answer) The target is " & target)

        ' The game is returned as a lambda expression. The lambda expression
        ' carries with it the environment in which it was created. This 
        ' environment includes the target number. Note that only the current
        ' guess is a parameter to the returned lambda expression, not the target. 

        ' Does the guess equal the target?
        Dim playTheGame = Function(guess As Integer) guess = target

        Return playTheGame

    End Function

End Module

下列範例示範巢狀 Lambda 運算式的廣泛存取權限。當傳回的 Lambda 運算式是從 Main 執行為 aDel 時,它會存取下列項目:

  • 在其中進行定義的類別 (Class) 欄位:aField

  • 在其中進行定義的類別屬性:aProp

  • 在其中進行定義之方法 functionWithNestedLambda 的參數:level1

  • functionWithNestedLambda 的本機變數:localVar

  • 形成巢狀之 Lambda 運算式的參數:level2

Module Module3

    Sub Main()
        ' Create an instance of the class, with 1 as the value of 
        ' the property.
        Dim lambdaScopeDemoInstance = New LambdaScopeDemoClass _
            With {.Prop = 1}

        ' Variable aDel will be bound to the nested lambda expression  
        ' returned by the call to functionWithNestedLambda.
        ' The value 2 is sent in for parameter level1.
        Dim aDel As aDelegate = _
            lambdaScopeDemoInstance.functionWithNestedLambda(2)

        ' Now the returned lambda expression is called, with 4 as the 
        ' value of parameter level3.
        Console.WriteLine("First value returned by aDel:   " & aDel(4))

        ' Change a few values to verify that the lambda expression has 
        ' access to the variables, not just their original values.
        lambdaScopeDemoInstance.aField = 20
        lambdaScopeDemoInstance.Prop = 30
        Console.WriteLine("Second value returned by aDel: " & aDel(40))
    End Sub

    Delegate Function aDelegate(ByVal delParameter As Integer) _
        As Integer

    Public Class LambdaScopeDemoClass
        Public aField As Integer = 6
        Dim aProp As Integer

        Property Prop() As Integer
            Get
                Return aProp
            End Get
            Set(ByVal value As Integer)
                aProp = value
            End Set
        End Property

        Public Function functionWithNestedLambda _
           (ByVal level1 As Integer) As aDelegate
            Dim localVar As Integer = 5

            ' When the nested lambda expression is executed the first 
            ' time, as aDel from Main, the variables have these values:
            ' level1 = 2
            ' level2 = 3, after aLambda is called in the Return statement
            ' level3 = 4, after aDel is called in Main
            ' locarVar = 5
            ' aField = 6
            ' aProp = 1
            ' The second time it is executed, two values have changed:
            ' aField = 20
            ' aProp = 30
            ' level3 = 40
            Dim aLambda = Function(level2 As Integer) _
                              Function(level3 As Integer) _
                                  level1 + level2 + level3 + localVar _
                                  + aField + aProp

            ' The function returns the nested lambda, with 3 as the 
            ' value of parameter level2.
            Return aLambda(3)
        End Function

    End Class
End Module

轉換為委派型別

Lambda 運算式可以隱含地轉換為相容的委派型別。如需一般相容性需求的詳細資訊,請參閱寬鬆委派轉換

此外,當您將 Lambda 運算式指派為委派時,可以指定參數名稱但略過其資料型別,以便從委派採用型別。在下列範例中,Lambda 運算式會指派至型別為 ExampleDel 且名稱為 del 的變數,此委派採用兩個參數,一個為整數、一個為字串。請注意,並未指定 Lambda 運算式中參數的資料型別。但是,del 需要整數引數和字串引數,如 ExampleDel 的定義中所指定。

' Definition of function delegate ExampleDel.
Delegate Function ExampleDel(ByVal arg1 As Integer, _
                             ByVal arg2 As String) As Integer
' Declaration of del as an instance of ExampleDel, with no data 
' type specified for the parameters, m and s.
Dim del As ExampleDel = Function(m, s) m

' Valid call to del, sending in an integer and a string.
Console.WriteLine(del(7, "up"))

' Neither of these calls is valid. Function del requires an integer
' argument and a string argument.
' Not valid.
' Console.WriteLine(del(7, 3))
' Console.WriteLine(del("abc"))

範例

  • 下列範例定義 Lambda 運算式,在可為 Null 的引數具有指派值時傳回 True,而其值為 Nothing 時傳回 False。

    Dim notNothing = Function(num? As Integer) _
                 num IsNot Nothing
    Dim arg As Integer = 14
    Console.WriteLine("Does the argument have an assigned value?")
    Console.WriteLine(notNothing(arg))
    
  • 下列範例定義 Lambda 運算式,會傳回陣列中最後一個元素的索引。

    Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    Dim lastIndex = Function(intArray() As Integer) _
                        intArray.Length - 1
    For i = 0 To lastIndex(numbers)
        numbers(i) = numbers(i) + 1
    Next
    

請參閱

工作

HOW TO:在 Visual Basic 中將程序傳遞至其他程序

HOW TO:建立 Lambda 運算式

概念

Visual Basic 中的程序

Visual Basic 中的 LINQ 簡介

委派和 AddressOf 運算子

可為 Null 的實值型別

寬鬆委派轉換

參考

Function 陳述式 (Visual Basic)