.NET Framework 3.5에서는 C#의 모든 대리자에서 대리자 형식과 메서드 시그니처를 일치시키는 분산 지원을 도입했습니다. 즉, 일치하는 서명이 있는 메서드뿐만 아니라 더 많은 파생 형식(공변성)을 반환하거나 대리자 형식에서 지정한 것보다 파생 형식(반공변성)이 적은 매개 변수를 허용하는 메서드에도 할당할 수 있습니다. 여기에는 제네릭 대리자와 제네릭이 아닌 대리자가 모두 포함됩니다.
예를 들어 제네릭과 제네릭이 아닌 두 개의 클래스와 두 개의 대리자가 있는 다음 코드를 고려해 보세요.
public class First { }
public class Second : First { }
public delegate First SampleDelegate(Second a);
public delegate R SampleGenericDelegate<A, R>(A a);
또는 SampleDelegate
형식의 SampleGenericDelegate<A, R>
대리자를 만들 때 다음 메서드 중 하나를 해당 대리자에게 할당할 수 있습니다.
// Matching signature.
public static First ASecondRFirst(Second second)
{ 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(); }
다음 코드 예제에서는 메서드 서명과 대리자 형식 간의 암시적 변환을 보여 줍니다.
// 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;
자세한 예제는 대리자에서 분산 사용(C#) 및 Func 및 Action 제네릭 대리자(C#)에 대한 분산 사용(C#)을 참조하세요.
제네릭 형식 매개 변수의 분산
.NET Framework 4 이상에서는 대리자 간에 암시적 변환을 사용하도록 설정할 수 있으므로 제네릭 형식 매개 변수로 지정된 형식이 다른 제네릭 대리자를 서로 할당할 수 있습니다( 분산에 필요한 경우 형식이 서로 상속되는 경우).
암시적 변환을 사용하도록 설정하려면 대리자의 제네릭 매개 변수를 키워드 `in
` 또는 `out
`을 사용하여 공변 또는 반공변으로 명시적으로 선언해야 합니다.
다음 코드 예제에서는 공변 제네릭 형식 매개 변수가 있는 대리자를 만드는 방법을 보여줍니다.
// 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;
}
변수 지원만 사용하여 메서드 시그니처를 대리자 형식과 일치시키고 c0 및 c1 키워드를 사용하지 않는 경우, 때로는 동일한 람다 식 또는 메서드로 대리자의 인스턴스를 생성할 수는 있지만, 한 대리자를 다른 대리자에게 할당할 수는 없습니다.
다음 코드 예제에서 SampleGenericDelegate<String>
는 SampleGenericDelegate<Object>
을 상속받았지만 String
로 명시적으로 변환될 수는 없습니다. 제네릭 매개 변수 T
를 키워드로 out
표시하여 이 문제를 해결할 수 있습니다.
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;
}
.NET에 변형 형식 매개 변수가 있는 제네릭 대리자
.NET Framework 4에는 여러 기존 제네릭 대리자에서 제네릭 형식 매개 변수에 대한 분산 지원이 도입되었습니다.
Action
네임스페이스 System의 대리자(예: Action<T>, Action<T1,T2>)Func
네임스페이스 System의 대리자(예: Func<TResult>, Func<T,TResult>)대리자 Predicate<T>
대리자 Comparison<T>
자세한 내용 및 예제는 Func 및 Action 제네릭 대리자(C#)에 대한 분산 사용을 참조하세요.
제네릭 대리자에서 변형 형식 매개변수 선언
제네릭 대리자가 공변 또는 반공변 제네릭 형식 매개 변수를 갖는 경우 변형 제네릭 대리자라고 할 수 있습니다.
키워드 out
를 사용하여 제네릭 대리자에서 제네릭 형식 매개 변수의 공변성을 선언할 수 있습니다. 공변 형식은 메서드 반환 형식으로만 사용할 수 있으며 메서드 인수의 형식으로는 사용할 수 없습니다. 다음 코드 예제에서는 공변 제네릭 대리자를 선언하는 방법을 보여줍니다.
public delegate R DCovariant<out R>();
제네릭 대리자에서 in
키워드를 사용하여 제네릭 타입 매개변수를 반변성으로 선언할 수 있습니다. 반공변성 형식은 메서드 반환 형식이 아닌 메서드 인수의 형식으로만 사용할 수 있습니다. 다음 코드 예제에서는 반공변 제네릭 대리자를 선언하는 방법을 보여줍니다.
public delegate void DContravariant<in A>(A a);
중요합니다
ref
, in
및 out
C#의 매개 변수를 변형으로 표시할 수 없습니다.
동일한 대리자에서 분산 및 공변성 모두를 지원할 수도 있지만 다른 형식 매개 변수에 대해서도 지원합니다. 이 방법은 다음 예제에서 확인할 수 있습니다.
public delegate R DVariant<in A, out R>(A a);
Variant 제네릭 대리자 인스턴스화 및 호출
고정 대리자를 인스턴스화하고 호출하는 것처럼 변형 대리자를 인스턴스화하고 호출할 수 있습니다. 다음 예제에서는 대리자가 람다 식으로 인스턴스화됩니다.
DVariant<String, String> dvariant = (String str) => str + " ";
dvariant("test");
변형된 제네릭 대리자 결합하기
변형 대리자를 결합하지 마세요. 이 메서드는 Combine 변형 대리자 변환을 지원하지 않으며 대리자가 정확히 동일한 형식이어야 합니다. 다음 코드 예제와 같이 메서드를 사용하거나 연산자를 사용하여 Combine+
대리자를 결합할 때 런타임 예외가 발생할 수 있습니다.
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);
값 및 참조 형식에 대한 제네릭 형식 매개 변수의 분산
제네릭 형식 매개 변수에 대한 분산은 참조 형식에 대해서만 지원됩니다. 예를 들어, 정수는 값 유형이기 때문에 DVariant<int>
을 DVariant<Object>
이나 DVariant<long>
로 암시적으로 변환할 수 없습니다.
다음 예제에서는 제네릭 형식 매개 변수의 분산이 값 형식에 대해 지원되지 않는 것을 보여 줍니다.
// 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;
}
참고하십시오
.NET