Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Платформа .NET Framework 3.5 представила поддержку несоответствия подписей методов с типами делегатов во всех делегатах в C# и Visual Basic. Это означает, что можно назначить делегатам не только методы, имеющие соответствующие сигнатуры, но и методы, возвращающие более производные типы (ковариантность) или принимающие параметры, имеющие менее производные типы (контравариантность), чем указанные типом делегата. Это включает как универсальные, так и не универсальные делегаты.
Например, рассмотрим следующий код, имеющий два класса и два делегата: универсальный и не универсальный.
Public Class First
End Class
Public Class Second
Inherits First
End Class
Public Delegate Function SampleDelegate(ByVal a As Second) As First
Public Delegate Function SampleGenericDelegate(Of A, R)(ByVal a As A) As R
При создании делегатов SampleDelegate или SampleDelegate(Of A, R) типов можно назначить один из следующих методов этим делегатам.
' Matching signature.
Public Shared Function ASecondRFirst(
ByVal second As Second) As First
Return New First()
End Function
' The return type is more derived.
Public Shared Function ASecondRSecond(
ByVal second As Second) As Second
Return New Second()
End Function
' The argument type is less derived.
Public Shared Function AFirstRFirst(
ByVal first As First) As First
Return New First()
End Function
' The return type is more derived
' and the argument type is less derived.
Public Shared Function AFirstRSecond(
ByVal first As First) As Second
Return New Second()
End Function
В следующем примере кода показано неявное преобразование между сигнатурой метода и типом делегата.
' Assigning a method with a matching signature
' to a non-generic delegate. No conversion is necessary.
Dim dNonGeneric As SampleDelegate = AddressOf ASecondRFirst
' Assigning a method with a more derived return type
' and less derived argument type to a non-generic delegate.
' The implicit conversion is used.
Dim dNonGenericConversion As SampleDelegate = AddressOf AFirstRSecond
' Assigning a method with a matching signature to a generic delegate.
' No conversion is necessary.
Dim dGeneric As SampleGenericDelegate(Of Second, First) = AddressOf ASecondRFirst
' Assigning a method with a more derived return type
' and less derived argument type to a generic delegate.
' The implicit conversion is used.
Dim dGenericConversion As SampleGenericDelegate(Of Second, First) = AddressOf AFirstRSecond
Дополнительные примеры см. в статье "Использование вариативности в делегатах (Visual Basic)" и "Использование вариативности для Func и Action Generic Delegates (Visual Basic)".
Дисперсия в параметрах универсального типа
В .NET Framework 4 и более поздних версиях доступно неявное преобразование между делегатами, что позволяет назначать универсальные делегаты с различными типами, заданными параметрами универсального типа, друг другу, если типы наследуются друг от друга, как требуется для вариативности.
Чтобы включить неявное преобразование, необходимо явно объявить универсальные параметры в делегате как ковариантные или контравариантные с помощью ключевого слова in или out.
В следующем примере кода показано, как создать делегат с ковариантным параметром универсального типа.
' Type T is declared covariant by using the out keyword.
Public Delegate Function SampleGenericDelegate(Of Out T)() As T
Sub Test()
Dim dString As SampleGenericDelegate(Of String) = Function() " "
' You can assign delegates to each other,
' because the type T is declared covariant.
Dim dObject As SampleGenericDelegate(Of Object) = dString
End Sub
Если вы используете только поддержку дисперсии для сопоставления подписей методов с типами делегатов и не используете ключевые слова in и out, то можете обнаружить, что иногда возможно создать экземпляры делегатов с идентичными лямбда-выражениями или методами, но нельзя присвоить один делегат другому.
В следующем примере кода невозможно явно преобразовать SampleGenericDelegate(Of String) в SampleGenericDelegate(Of Object), хотя String является наследником Object. Эту проблему можно устранить, пометив универсальный параметр T ключевым словом out .
Public Delegate Function SampleGenericDelegate(Of T)() As T
Sub Test()
Dim dString As SampleGenericDelegate(Of String) = Function() " "
' You can assign the dObject delegate
' to the same lambda expression as dString delegate
' because of the variance support for
' matching method signatures with delegate types.
Dim dObject As SampleGenericDelegate(Of Object) = Function() " "
' The following statement generates a compiler error
' because the generic type T is not marked as covariant.
' Dim dObject As SampleGenericDelegate(Of Object) = dString
End Sub
Универсальные делегаты с параметрами типа variant в .NET Framework
Платформа .NET Framework 4 ввела поддержку для вариативности параметров обобщённого типа в нескольких уже существующих обобщённых делегатах.
Actionделегаты из пространства имен System, например, Action<T> и Action<T1,T2>Funcделегаты из пространства имен System, например, Func<TResult> и Func<T,TResult>Делегат Predicate<T>
Делегат Comparison<T>
Делегат Converter<TInput,TOutput>
Дополнительные сведения и примеры см. в разделе «Использование вариативности для обобщённых делегатов Func и Action (Visual Basic)».
Объявление параметров типа ковариантных и контрвариантных в обобщённых делегатах
Если универсальный делегат имеет ковариантные или контравариантные параметры универсального типа, он может называться вариантным универсальным делегатом.
Параметр универсального типа можно объявить ковариантным в универсальном делегате с помощью ключевого out слова. Ковариантный тип можно использовать только в качестве типа возвращаемого метода, а не в качестве типа аргументов метода. В следующем примере кода показано, как объявить ковариантный универсальный делегат.
Public Delegate Function DCovariant(Of Out R)() As R
Параметр универсального типа можно объявить контравариантным в универсальном делегате с помощью ключевого слова in. Контравариантный тип можно использовать только в качестве типа аргументов метода, а не в качестве возвращаемого типа метода. В следующем примере кода показано, как объявить контравариантный универсальный делегат.
Public Delegate Sub DContravariant(Of In A)(ByVal a As A)
Это важно
ByRef параметры в Visual Basic не могут быть помечены как вариант.
Кроме того, можно поддерживать дисперсию и ковариацию в одном делегате, но для разных параметров типов. Это показано в следующем примере.
Public Delegate Function DVariant(Of In A, Out R)(ByVal a As A) As R
Создание экземпляров и вызов вариантных универсальных делегатов.
Вы можете создавать экземпляры вариантных делегатов и вызывать их точно так же, как создавать и вызывать экземпляры инвариантных делегатов. В следующем примере делегат создается при помощи лямбда-выражения.
Dim dvariant As DVariant(Of String, String) = Function(str) str + " "
dvariant("test")
Объединение обобщённых делегатов с вариативностью
Не следует объединять вариативные делегаты. Метод Combine не поддерживает преобразование вариантов делегатов и ожидает, что делегаты будут иметь точно тот же тип. Это может привести к исключению во время выполнения при объединении делегатов с помощью метода Combine (в C# и Visual Basic) или оператора + (в C#), как показано в следующем примере кода.
Dim actObj As Action(Of Object) = Sub(x) Console.WriteLine("object: {0}", x)
Dim actStr As Action(Of String) = Sub(x) Console.WriteLine("string: {0}", x)
' The following statement throws an exception at run time.
' Dim actCombine = [Delegate].Combine(actStr, actObj)
Дисперсия в параметрах универсального типа для типов значений и ссылочных типов
Вариативность параметров универсального типа поддерживается только для ссылочных типов. Например, DVariant(Of Int)нельзя неявно преобразовать в DVariant(Of Object) или DVariant(Of Long), так как целое число является типом значения.
В следующем примере показано, что дисперсии в параметрах универсального типа не поддерживаются для типов значений.
' The type T is covariant.
Public Delegate Function DVariant(Of Out T)() As T
' The type T is invariant.
Public Delegate Function DInvariant(Of T)() As T
Sub Test()
Dim i As Integer = 0
Dim dInt As DInvariant(Of Integer) = Function() i
Dim dVariantInt As DVariant(Of Integer) = Function() i
' All of the following statements generate a compiler error
' because type variance in generic parameters is not supported
' for value types, even if generic type parameters are declared variant.
' Dim dObject As DInvariant(Of Object) = dInt
' Dim dLong As DInvariant(Of Long) = dInt
' Dim dVariantObject As DInvariant(Of Object) = dInt
' Dim dVariantLong As DInvariant(Of Long) = dInt
End Sub
Упрощенное преобразование делегатов в Visual Basic
Упрощённое преобразование делегатов обеспечивает большую гибкость при сопоставлении сигнатур методов с типами делегатов. Например, он позволяет опустить спецификации параметров и опустить возвращаемые значения функции при назначении метода делегату. Дополнительные сведения см. в разделе "Упрощенное преобразование делегатов".