Поделиться через


Лямбда-выражения

Обновлен: Ноябрь 2007

Лямбда-выражения является функцией без имени, которая вычисляет и возвращает одиночное значение. Лямбда-выражения можно использовать везде, где допустимы типы делегата.

Bb531253.alert_note(ru-ru,VS.90).gifПримечание.

Исключением является оператор RemoveHandler. Невозможно передать лямбда-выражение в качестве параметра делегата RemoveHandler.

В следующем примере лямбда-выражение увеличивает значение своего аргумента и возвращает его.

Function (num As Integer) num + 1

Поскольку лямбда-выражение является выражением, его можно использовать только в составе оператора.

Например, можно присвоить функцию переменной, особенно если ее значение требуется использовать несколько раз.

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))

Лямбда-выражения могут быть возвращены как значение вызванной функции (как это показано в примере в разделе "Контекст" ниже в этом разделе), или могут быть переданными в качестве аргумента в параметр делегата. В следующем примере лямбда-выражения типа Boolean передаются в качестве аргумента в метод testResult. Метод применяет логическую проверку целочисленного аргумента value и отображает сообщение об успешности (лямбда-выражение возвращает True и присваивает это значение value) или ошибке (лямбда-выражение возвращает False).

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

Лямбда-выражения в запросах

В LINQ (Language-Integrated Query) лямбда-выражения лежат в основе многих стандартных операторов запроса. Компилятор создает лямбда-выражения для записи вычислений, которые определены в основных методах запроса, таких, как 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).

Синтаксис лямбда-выражений

Синтаксис лямбда-выражения схож с синтаксисом стандартной функции. Различия заключаются в следующем:

  • Лямбда-выражение не имеет имени.

  • Лямбда-выражения не могут включать модификаторы, такие как Overloads или Overrides.

  • Лямбда-выражения не используют предложение As для обозначения типа возвращаемого значения функции. Вместо этого тип выводится из значения, которое вычисляется в теле лямбда-выражения. Например, если тело лямбда-выражения — Where cust.City = "London", возвращается тип Boolean.

  • Тело функции должно быть выражением, а не оператором. Тело может содержать вызов процедуры Function, но не вызов процедуры Sub.

  • Отсутствует оператор Return. Значение, возвращаемое функцией, является значением выражения в теле функции.

  • Отсутствует оператор End Function.

  • Все параметры должны иметь определенный или выводимый тип данных.

  • Параметры Optional и Paramarray не разрешены.

  • Универсальные параметры не разрешены.

В связи с указанными ограничениями и особенностями использования лямбда-выражения обычно представляют собой короткие и упрощенные выражения.

Контекст

Лямбда-выражение использует общий контекст с методом, внутри которого оно определено. Оно имеет те же права доступа что и код, содержащийся в методе. Это включает доступ к переменным членов, функциям, процедурам, Me, а также параметрам и локальным переменным в содержащем методе.

Доступ к локальным переменным и параметрам в содержащем методе можно продлить сверх времени существования этого метода. До тех пор, пока делегат, ссылающийся на делегат лямбда-выражения, недоступен сборщику мусора, доступ к переменным среды исходного кода сохраняется. В следующем примере переменная target является локальной для метода makeTheGame, в котором определено лямбда-выражение playTheGame. Обратите внимание, что возвращаемое лямбда-выражение, присваивается takeAGuess в Main, который по-прежнему сохраняет доступ к локальной переменной 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

В следующем примере показан широкий спектр прав доступа вложенных лямбда-выражений. При выполнении возвращаемого лямбда-выражения из Main как aDel, он обращается к следующим элементам:

  • Поле класса, в котором он определен: aField.

  • Свойство класса, в котором он определен: aProp.

  • Параметр метода functionWithNestedLambda, в котором он определен: level1.

  • Локальная переменная functionWithNestedLambda: localVar.

  • Параметр лямбда-выражения, в котором он является вложенным: 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

Преобразование к типу делегата

Лямбда-выражения могут быть неявно преобразованы к совместимому типу делегата. Дополнительные сведения об общих требованиях к совместимости см. в разделе Ослабленное преобразование делегата.

Кроме того, при присваивании лямбда-выражения делегатам можно указать имена параметров, но опустить их типы, позволяя принимать типы из делегата. В следующем примере лямбда-выражению присваивается переменная с именем del из типа делегата ExampleDel, который принимает два параметра — целого и строкового типа. Обратите внимание, что типы данных параметров в лямбда-выражении не определены. Однако 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"))

Примеры

  • В следующем примере определяется лямбда-выражение, которое возвращает True, если аргументу типа nullable было присвоено значение, и False, если аргумент имеет значение Nothing.

    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))
    
  • В следующем примере определяется лямбда-выражение, возвращающее индекс последнего элемента в массиве.

    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
    

См. также

Задачи

Практическое руководство. Передача процедур другой процедуре в Visual Basic

Практическое руководство. Создание лямбда-выражения

Основные понятия

Процедуры в Visual Basic

Знакомство с LINQ в Visual Basic

Делегаты и оператор AddressOf

Типы значения Null

Ослабленное преобразование делегата

Ссылки

Оператор Function (Visual Basic)