Variação em delegações (C# e Visual Basic)
.NET Framework 3.5 e Visual Studio de 2008 oferece suporte à variação assinaturas de método de correspondência com os tipos de delegados em todos os delegados no C# e Visual Basic. Isso significa que você pode atribuir a delega não apenas os métodos que possuem assinaturas correspondentes, mas também métodos que retornam mais derivado tipos (covariância) ou que aceitam parâmetros que têm menos tipos derivados (/ contravariância) não especificados pelo tipo delegate. Isso inclui representantes genéricos e não genérico.
Por exemplo, considere o seguinte código, que tem duas classes e dois delegados: genérico e não genérico.
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
public class First { }
public class Second : First { }
public delegate First SampleDelegate(Second a);
public delegate R SampleGenericDelegate<A, R>(A a);
Quando você cria os delegados da SampleDelegate ou SampleGenericDelegate<A, R> (SampleDelegate(Of A, R) em Visual Basic) tipos, você pode atribuir qualquer um dos seguintes métodos para os representantes.
' 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
// Matching signature.
public static First ASecondRFirst(Second first)
{ return new First(); }
// The return type is more derived.
public static Second ASecondRSecond(Second second)
{ return new Second(); }
// The argument type is less derived.
public static First AFirstRFirst(First first)
{ return new First(); }
// The return type is more derived
// and the argument type is less derived.
public static Second AFirstRSecond(First first)
{ return new Second(); }
O exemplo de código a seguir ilustra a conversão implícita entre a assinatura do método e o tipo de delegado.
' 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
// Assigning a method with a matching signature
// to a non-generic delegate. No conversion is necessary.
SampleDelegate dNonGeneric = 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.
SampleDelegate dNonGenericConversion = AFirstRSecond;
// Assigning a method with a matching signature to a generic delegate.
// No conversion is necessary.
SampleGenericDelegate<Second, First> dGeneric = ASecondRFirst;
// Assigning a method with a more derived return type
// and less derived argument type to a generic delegate.
// The implicit conversion is used.
SampleGenericDelegate<Second, First> dGenericConversion = AFirstRSecond;
Para obter mais exemplos, consulte Usando variação em delegações (C# e Visual Basic) e Usando variação para delegações genéricas Func e Action (C# e Visual Basic).
Variação nos parâmetros de tipo genérico
No.NET Framework 4, você pode habilitar a conversão implícita entre delegados, para que possam ser atribuídos a representantes genéricos que têm tipos diferentes, especificados pelo parâmetro de tipo genérico umas às outras, se os tipos são herdados uns dos outros, conforme exigido pela variação.
Para ativar a conversão implícita, você deve declarar explicitamente parâmetros genéricos em um delegado como covariant ou contravariant usando o in ou out palavra-chave.
O exemplo de código a seguir mostra como você pode criar um delegado que tem um parâmetro de tipo genérico covariant.
' 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
// Type T is declared covariant by using the out keyword.
public delegate T SampleGenericDelegate <out T>();
public static void Test()
{
SampleGenericDelegate <String> dString = () => " ";
// You can assign delegates to each other,
// because the type T is declared covariant.
SampleGenericDelegate <Object> dObject = dString;
}
Se você usar somente oferecem suporte a variação para coincidir com as assinaturas de método com delegar tipos e não use o in e out palavras-chave, você pode descobrir que às vezes, você pode instanciar delegados com expressões lambda idênticos ou métodos, mas não é possível atribuir um delegado para outro.
No exemplo de código a seguir, SampleGenericDelegate<String> não podem ser convertidas explicitamente para SampleGenericDelegate<Object> (SampleGenericDelegate(Of String) para SampleGenericDelegate(Of Object) em Visual Basic), apesar de String herda Object. Você pode corrigir esse problema, marcando o parâmetro genérico T com o out palavra-chave.
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
public delegate T SampleGenericDelegate<T>();
public static void Test()
{
SampleGenericDelegate<String> dString = () => " ";
// 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.
SampleGenericDelegate<Object> dObject = () => " ";
// The following statement generates a compiler error
// because the generic type T is not marked as covariant.
// SampleGenericDelegate <Object> dObject = dString;
}
Representantes genéricos que têm variante Digite parâmetros na.NET Framework
.NET Framework 4 introduz o suporte de variação para os parâmetros de tipo genérico em vários representantes de genéricos existentes:
Actiondelega a partir do System espaço para nome, por exemplo, Action eAction
Funcdelega a partir do System espaço para nome, por exemplo, Func eFunc
O Predicate delegar
O Comparison delegar
O Converter delegar
Para mais informações e exemplos, consulte Usando variação para delegações genéricas Func e Action (C# e Visual Basic).
Declarar parâmetros de tipo Variant em representantes genéricos
Se um delegado genérico tem covariant ou contravariant parâmetros de tipo genérico, ela pode ser chamada de um variante genérico delegar.
Você pode declarar um parâmetro de tipo genérico covariant em um delegado genérico usando a out palavra-chave. O tipo covariant pode ser usado apenas como um tipo de retorno do método e não como um tipo de argumentos do método. O exemplo de código a seguir mostra como declarar um delegado genérico covariant.
Public Delegate Function DCovariant(Of Out R)() As R
public delegate R DCovariant<out R>();
Você pode declarar um contravariant de parâmetro de tipo genérico em um delegado genérico usando a in palavra-chave. O tipo contravariant pode ser usado apenas como um tipo de argumentos do método e não como um tipo de retorno do método. O exemplo de código a seguir mostra como declarar um delegado genérico do contravariant.
Public Delegate Sub DContravariant(Of In A)(ByVal a As A)
public delegate void DContravariant<in A>(A a);
Importante
ByRefparâmetros no Visual Basic e ref e out parâmetros no C# e não pode ser marcado como variante.
Também é possível oferecer suporte a variação e a covariância o mesmo delegado, mas para os parâmetros de tipo diferente. Isto é mostrado no exemplo a seguir.
Public Delegate Function DVariant(Of In A, Out R)(ByVal a As A) As R
public delegate R DVariant<in A, out R>(A a);
Criar uma instância e invocando representantes genéricos da variante
Você pode instanciar e invocar variant delegados exatamente como você instancia e chama delegados invariável. No exemplo a seguir, o delegado é instanciado por uma expressão lambda.
Dim dvariant As DVariant(Of String, String) = Function(str) str + " "
dvariant("test")
DVariant<String, String> dvariant = (String str) => str + " ";
dvariant("test");
Combinando representantes genéricos da variante
Não, você deve combinar delegates variant. O Combine método não oferece suporte à conversão de delegado variant e delegados para ter exatamente o mesmo tipo de espera. Isso pode levar a uma exceção de tempo de execução quando você combina delegados usando o Combine método (em C# e Visual Basic) ou usando o + operador (em C#), conforme mostrado no exemplo de código a seguir.
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)
Action<object> actObj = x => Console.WriteLine("object: {0}", x);
Action<string> actStr = x => Console.WriteLine("string: {0}", x);
// All of the following statements throw exceptions at run time.
// Action<string> actCombine = actStr + actObj;
// actStr += actObj;
// Delegate.Combine(actStr, actObj);
Variação nos parâmetros de tipo genérico para tipos de referência e valor
É compatível com variação de parâmetros de tipo genérico somente tipos de referência. Por exemplo, DVariant<int> (DVariant(Of Int) em Visual Basic) não pode ser convertido implicitamente em DVariant<Object> ou DVaraint<long> (DVariant(Of Object) ou DVaraint(Of Long) em Visual Basic), porque o número inteiro é um tipo de valor.
O exemplo a seguir demonstra essa variação no tipo genérico parâmetros não tem suporte para tipos de valor.
' 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 dVaraintInt 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 dVaraintObject As DInvariant(Of Object) = dInt
' Dim dVaraintLong As DInvariant(Of Long) = dInt
End Sub
// The type T is covariant.
public delegate T DVariant<out T>();
// The type T is invariant.
public delegate T DInvariant<T>();
public static void Test()
{
int i = 0;
DInvariant<int> dInt = () => i;
DVariant<int> dVariantInt = () => 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.
// DInvariant<Object> dObject = dInt;
// DInvariant<long> dLong = dInt;
// DVariant<Object> dVariantObject = dVariantInt;
// DVariant<long> dVariantLong = dVariantInt;
}
Conversão de delegado reduzida em Visual Basic
Conversão de delegado relaxados, introduzido no Visual Basic de 2008, permite mais flexibilidade na correspondência de assinaturas de método com tipos delegate. Por exemplo, ele permite omitir as especificações do parâmetro e omitir os valores de retorno da função quando você atribui um método a um delegado. Para obter mais informações, consulte Conversão de delegado reduzida (Visual Basic).
Consulte também
Tarefas
Como combinar delegados (delegados multicast) (Guia de Programação em C#)
Referência
Usando variação para delegações genéricas Func e Action (C# e Visual Basic)