Udostępnij za pośrednictwem


Wariancje w delegatach (C# i Visual Basic)

.NET Framework 3.5 i Visual Studio 2008 wprowadzone odchylenie obsługę dopasowania podpisy metod z typami delegata wszystkich delegatów w C# i Visual Basic.Oznacza to, że można przypisać deleguje nie tylko metody, które mają odpowiadające sobie podpisów, ale także metody, które zwracają więcej pochodnych typów (kowariancja), lub że akceptować parametry, które mają mniej pochodnych typów (kontrawariancja) niż ten określony przez typ obiektu delegowanego.Obejmuje to rodzajowe i nierodzajową delegatów.

Na przykład, rozważmy następujący kod, który ma dwie klasy i dwóch delegatów: ogólne i nierodzajową.

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

Podczas tworzenia delegatów SampleDelegate lub SampleGenericDelegate<A, R> (SampleDelegate(Of A, R) w języku Visual Basic) typów, można przypisać jednej z następujących metod do tych delegatów.

' 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(); }

Poniższy przykład kodu pokazuje niejawna konwersja między podpis metody i typ obiektu delegowanego.

' 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;

Aby uzyskać więcej przykładów, zobacz Korzystanie z wariancji w delegatach (C# i Visual Basic) i Korzystanie z wariancji dla delegatów Func i Action (C# i Visual Basic).

WARIANCJA parametry typu rodzajowego

W programie.NET Framework 4, można włączyć niejawna konwersja między delegatów, tak aby rodzajowy delegatów, które mają różne typy określonej przez parametr typu rodzajowego mogą być przypisane do siebie nawzajem, jeśli typy są dziedziczone od siebie, zgodnie z wymaganiami odchylenie.

Aby włączyć niejawna konwersja, należy jawnie deklarować parametry rodzajowe w delegata jako kowariantnego lub kontrawariantnego za pomocą in lub out słowa kluczowego.

Poniższy przykład kodu pokazuje, jak można utworzyć obiektu delegowanego, który ma parametr typu rodzajowego kowariantnego.

' 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;           
}

Jeśli używasz obsługują tylko wariancja odpowiadać podpisy metod z delegować typów i nie należy używać in i out słowa kluczowe, mogą znaleźć że czasami można utworzyć wystąpienia delegatów z wyrażenia lambda identyczne lub metody, ale nie można przypisać jeden delegat do innego.

W poniższym przykładzie kodu SampleGenericDelegate<String> nie można jawnie skonwertować na SampleGenericDelegate<Object> (SampleGenericDelegate(Of String) do SampleGenericDelegate(Of Object) w języku Visual Basic), chociaż String dziedziczy Object.Można rozwiązać ten problem poprzez znakowanie parametru rodzajowego T z out słowa kluczowego.

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;



}

Rodzajowy delegatów, które mają wariant wpisz parametry w.NET Framework

.NET Framework 4 wprowadzono obsługę odchylenie parametry typu rodzajowego w kilku istniejących rodzajowy delegatów:

Aby uzyskać dodatkowe informacje i przykłady, zobacz Korzystanie z wariancji dla delegatów Func i Action (C# i Visual Basic).

Deklarowanie parametrów typu Variant w delegatów rodzajowy

Jeśli Delegat rodzajowy ma kowariantnego lub kontrawariantnego parametry typu rodzajowego, to można dalej zwane delegować wariant generic.

Można zadeklarować parametr typu rodzajowego kowariantnego w Delegat rodzajowy za pomocą out słowa kluczowego.Typu kowariantnego mogą służyć jedynie jako typ zwracany metody, a nie typ argumenty tej metody.Poniższy przykład kodu pokazuje jak deklarować kowariantnego Delegat rodzajowy.

Public Delegate Function DCovariant(Of Out R)() As R
public delegate R DCovariant<out R>();

Można zadeklarować kontrawariantnego parametr typu rodzajowego w Delegat rodzajowy za pomocą in słowa kluczowego.Typ kontrawariantnego mogą służyć jedynie jako typ argumenty tej metody, a nie typu powrotu metody.Poniższy przykład kodu pokazuje jak deklarować Delegat rodzajowy kontrawariantnego.

Public Delegate Sub DContravariant(Of In A)(ByVal a As A)
public delegate void DContravariant<in A>(A a);
Ważna uwagaWażne

ByRefParametry w języku Visual Basic i ref i out parametrów w języku C# i nie może być oznaczony jako wariant.

Jest również możliwe obsługuje zarówno wariancji i Kowariancja w samego obiektu delegowanego, ale dla różnych typów parametrów.To jest pokazane w następującym przykładzie.

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

Utworzenie wystąpienia i wywoływanie delegatów rodzajowy wariant

Można utworzyć wystąpienia i wywołać wariantu delegatów, podobnie jak wystąpienia i wywołać niezmienny delegatów.W poniższym przykładzie delegata jest uruchomiony przez wyrażenie lambda.

Dim dvariant As DVariant(Of String, String) = Function(str) str + " "
dvariant("test")
DVariant<String, String> dvariant = (String str) => str + " ";
dvariant("test");

Łączenie delegatów rodzajowy wariant

Nie należy wpisywać wariantu delegatów.Combine Metoda nie obsługuje konwersji obiektu delegowanego typu variant i oczekuje, że delegatów być tego samego typu.Może to prowadzić do wyjątek czasu wykonywania, podczas łączenia się z delegatów, albo przy użyciu Combine metody (w języku C# i Visual Basic) lub za pomocą + operatora (w języku C#), jak pokazano w poniższym przykładzie kodu.

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

WARIANCJA parametry rodzajowe typ wartości i typy odwołań

Wariancja dla parametrów typu rodzajowego jest obsługiwana dla tylko typy odwołań.Na przykład DVariant<int> (DVariant(Of Int) w języku Visual Basic) nie można niejawnie przekonwertować na DVariant<Object> lub DVaraint<long> (DVariant(Of Object) lub DVaraint(Of Long) w języku Visual Basic), ponieważ liczba całkowita jest typ wartości.

Poniższy przykład demonstruje, że odchylenia w typie rodzajowym parametrów nie jest obsługiwany dla typów wartości.

' 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;            
}

Obniżone konwersji obiektu delegowanego w języku Visual Basic

Konwersji obniżone pełnomocnika, wprowadzone w 2008 Visual Basic umożliwia większą elastyczność w dopasowania podpisy metod z typów obiektów delegowanych.Na przykład umożliwia pominięcie parametru specyfikacji i pominąć wartości zwracane funkcji, gdy metoda przypisać pełnomocnika.Aby uzyskać więcej informacji, zobacz Swobodna konwersja delegatów (Visual Basic).

Zobacz też

Zadania

Porady: łączenie obiektów delegowanych (obiekty delegowane multiemisji) (Przewodnik programowania w języku C#)

Informacje

Korzystanie z wariancji dla delegatów Func i Action (C# i Visual Basic)

Inne zasoby

Typy ogólne w oprogramowaniu .NET Framework