Неявное преобразование делегата (Visual Basic)

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

Параметры и тип возвращаемого значения

Вместо сопоставления точной сигнатуры ослабленное преобразование требует следующих условий при установке Option Strict в On:

  • Должно существовать расширяющее преобразование типа данных каждого параметра делегата к типу данных соответствующего параметра назначенной функции или Sub. В следующем примере делегат Del1 имеет один параметр типа Integer. Параметр m в назначенном лямбда-выражении должен иметь тип данных для которых имеется расширяющее преобразование из Integer, например Long или Double.

    ' Definition of delegate Del1. 
    Delegate Function Del1(ByVal arg As Integer) As Integer
    
    ' Valid lambda expression assignments with Option Strict on or off: 
    
    ' Integer matches Integer. 
    Dim d1 As Del1 = Function(m As Integer) 3
    
    ' Integer widens to Long 
    Dim d2 As Del1 = Function(m As Long) 3
    
    ' Integer widens to Double 
    Dim d3 As Del1 = Function(m As Double) 3
    

    Сужающие преобразования разрешены только в том случае, если Option Strict имеет значение Off.

    ' Valid only when Option Strict is off: 
    
    Dim d4 As Del1 = Function(m As String) CInt(m)
    Dim d5 As Del1 = Function(m As Short) m
    
  • Должно существовать расширяющее преобразование в обратном направлении из возвращаемого типа назначенной функции или Sub к возвращаемому типу делегата. В следующих примерах, основная часть каждого назначенного лямбда-выражения должно иметь значение типа данных, не большего по разрядности, чем Integer, так как возвращаемым типом del1 является тип Integer.

    ' Valid return types with Option Strict on: 
    
    ' Integer matches Integer. 
    Dim d6 As Del1 = Function(m As Integer) m
    
    ' Short widens to Integer. 
    Dim d7 As Del1 = Function(m As Long) CShort(m)
    
    ' Byte widens to Integer. 
    Dim d8 As Del1 = Function(m As Double) CByte(m)
    

Если Option Strict имеет значение Off, расширяющее ограничение снимается в обоих направлениях.

' Valid only when Option Strict is set to Off. 

' Integer does not widen to Short in the parameter. 
Dim d9 As Del1 = Function(n As Short) n

' Long does not widen to Integer in the return type. 
Dim d10 As Del1 = Function(n As Integer) CLng(n)

Пропуск параметра спецификации

Ослабленные делегаты также позволяют полностью опустить параметры спецификации в назначенном методе:

' Definition of delegate Del2, which has two parameters. 
Delegate Function Del2(ByVal arg1 As Integer, ByVal arg2 As String) As Integer
' The assigned lambda expression specifies no parameters, even though 
' Del2 has two parameters. Because the assigned function in this  
' example is a lambda expression, Option Strict can be on or off. 
' Compare the declaration of d16, where a standard function is assigned. 
Dim d11 As Del2 = Function() 3

' The parameters are still there, however, as defined in the delegate.
Console.WriteLine(d11(5, "five"))

' Not valid. 
' Console.WriteLine(d11()) 
' Console.WriteLine(d11(5))

Обратите внимание, что не удается задать некоторые параметры и не указать другие.

' Not valid. 
'Dim d12 As Del2 = Function(p As Integer) p

Возможность опустить параметры является полезной в ситуации, например при определении обработчика событий, где включены несколько сложных параметров. Аргументы для некоторых обработчиков событий не используются. Вместо этого обработчик непосредственно получает состояние элемента управления, к которому привязано событие, а аргументы игнорируются. Ослабленные делегаты позволяют опустить аргументы в таких объявлениях, когда результат неоднозначен. В следующем примере полностью заданный метод OnClick можно переписать как RelaxedOnClick.

Sub OnClick(ByVal sender As Object, ByVal e As EventArgs) Handles b.Click
    MessageBox.Show("Hello World from" + b.Text)
End Sub

Sub RelaxedOnClick() Handles b.Click
    MessageBox.Show("Hello World from" + b.Text)
End Sub

Примеры AddressOf

Лямбда-выражения используются в предыдущих примерах, чтобы облегчить наблюдение за связью между типами. Однако ослабление разрешено для назначений делегата, которые используют AddressOf, Handles или AddHandler.

В следующем примере функции f1, f2, f3 и f4 могут быть назначены Del1.

' Definition of delegate Del1. 
Delegate Function Del1(ByVal arg As Integer) As Integer
' Definitions of f1, f2, f3, and f4. 
Function f1(ByVal m As Integer) As Integer 
End Function 

Function f2(ByVal m As Long) As Integer 
End Function 

Function f3(ByVal m As Integer) As Short 
End Function 

Function f4() As Integer 
End Function
' Assignments to function delegate Del1. 

' Valid AddressOf assignments with Option Strict on or off: 

' Integer parameters of delegate and function match. 
Dim d13 As Del1 = AddressOf f1

' Integer delegate parameter widens to Long. 
Dim d14 As Del1 = AddressOf f2

' Short return in f3 widens to Integer. 
Dim d15 As Del1 = AddressOf f3

Следующей пример справедлив только в том случае, если Option Strict имеет значение Off.

' If Option Strict is Off, parameter specifications for f4 can be omitted. 
Dim d16 As Del1 = AddressOf f4

' Function d16 still requires a single argument, however, as specified 
' by Del1.
Console.WriteLine(d16(5))

' Not valid. 
'Console.WriteLine(d16()) 
'Console.WriteLine(d16(5, 3))

Игнорирование возвращаемого значения функции

Ослабленный делегат преобразования позволяет назначить функцию делегату Sub, при этом игнорируя значение, возвращаемое функцией. Однако присвоить Sub делегату функции невозможно. В следующем примере адрес функции doubler присваивается делегату Sub Del3.

' Definition of Sub delegate Del3. 
Delegate Sub Del3(ByVal arg1 As Integer)

' Definition of function doubler, which both displays and returns the 
' value of its integer parameter. 
Function doubler(ByVal p As Integer) As Integer 
    Dim times2 = 2 * p
    Console.WriteLine("Value of p: " & p)
    Console.WriteLine("Double p:   " & times2)
    Return times2
End Function
' You can assign the function to the Sub delegate: 
Dim d17 As Del3 = AddressOf doubler

' You can then call d17 like a regular Sub procedure.
d17(5)

' You cannot call d17 as a function. It is a Sub, and has no  
' return value. 
' Not valid. 
'Console.WriteLine(d17(5))

См. также

Задачи

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

Ссылки

Оператор Option Strict

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

Лямбда-выражения (Visual Basic)

Расширяющие и сужающие преобразования (Visual Basic)

Вывод локального типа (Visual Basic)

Другие ресурсы

Делегаты (Visual Basic)