다음을 통해 공유


제네릭 인터페이스의 가변성(C# 및 Visual Basic)

.NET Framework 4에는 기존의 여러 제네릭 인터페이스에 대한 가변성(variance) 지원이 추가되었습니다. 가변성(variance) 지원을 사용하면 이러한 인터페이스를 구현하는 클래스를 암시적으로 변환할 수 있습니다. 현재 variant 인터페이스에는 다음과 같은 것들이 있습니다.

공 분산은 메서드가 파생된 반환 형식을 인터페이스의 제네릭 형식 매개 변수에 정의된 것보다 더 많이 가질 수 있도록 합니다. 제네릭 인터페이스인 IEnumerable<Object> 및 IEnumerable<String>(Visual Basic의 경우 IEnumerable(Of Object) 및 IEnumerable(Of String))은 공 분산 기능을 잘 설명합니다. IEnumerable<String>(Visual Basic의 경우 IEnumerable(Of String)) 인터페이스는 IEnumerable<Object> 인터페이스(Visual Basic의 경우 IEnumerable(Of Object))를 상속하지 않습니다. 그러나 String 형식은 Object 형식을 상속하며, 경우에 따라 이러한 인터페이스의 개체를 서로 할당할 수도 있습니다. 이는 다음 코드 예제에서 확인할 수 있습니다.

Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings
IEnumerable<String> strings = new List<String>();
IEnumerable<Object> objects = strings;

이전 버전의 .NET Framework에서는 이 코드가 Visual Basic(Option Strict On과 함께 사용하는 경우)과 C#에서 컴파일 오류를 일으켰습니다. 그러나 이제는 IEnumerable<T> 인터페이스가 공변(covariant)이기 때문에 이전 예제와 같이 objects 대신 strings를 사용할 수 있습니다.

반공변성(Contravariance)은 메서드가 파생된 인수 형식을 인터페이스의 제네릭 매개 변수에 지정된 것보다 더 적게 가질 수 있도록 합니다. 반공변성(Contravariance)을 설명하기 위해 BaseComparer 클래스를 만들어 BaseClass 클래스의 인스턴스를 비교했다고 가정해 보겠습니다. BaseComparer 클래스는 IEqualityComparer<BaseClass> 인터페이스(Visual Basic의 경우 IEqualityComparer(Of BaseClass))를 구현합니다. 이제 IEqualityComparer<T> 인터페이스가 반공변(contravariant)이기 때문에 BaseComparer를 사용하여 BaseClass 클래스를 상속하는 클래스의 인스턴스를 비교할 수 있습니다. 이는 다음 코드 예제에서 확인할 수 있습니다.

' Simple hierarchy of classes.
Class BaseClass
End Class

Class DerivedClass
    Inherits BaseClass
End Class

' Comparer class.
Class BaseComparer
    Implements IEqualityComparer(Of BaseClass)

    Public Function Equals1(ByVal x As BaseClass,
                            ByVal y As BaseClass) As Boolean _
                            Implements IEqualityComparer(Of BaseClass).Equals
        Return (x.Equals(y))
    End Function

    Public Function GetHashCode1(ByVal obj As BaseClass) As Integer _
        Implements IEqualityComparer(Of BaseClass).GetHashCode
        Return obj.GetHashCode
    End Function
End Class
Sub Test()
    Dim baseComparer As IEqualityComparer(Of BaseClass) = New BaseComparer
    ' Implicit conversion of IEqualityComparer(Of BaseClass) to 
    ' IEqualityComparer(Of DerivedClass).
    Dim childComparer As IEqualityComparer(Of DerivedClass) = baseComparer
End Sub
// Simple hierarchy of classes.
class BaseClass { }
class DerivedClass : BaseClass { }

// Comparer class.
class BaseComparer : IEqualityComparer<BaseClass> 
{
    public int GetHashCode(BaseClass baseInstance)
    {
        return baseInstance.GetHashCode();
    }
    public bool Equals(BaseClass x, BaseClass y)
    {
        return x == y;
    }
}
class Program
{
    static void Test()
    {
        IEqualityComparer<BaseClass> baseComparer = new BaseComparer();

        // Implicit conversion of IEqualityComparer<BaseClass> to 
        // IEqualityComparer<DerivedClass>.
        IEqualityComparer<DerivedClass> childComparer = baseComparer;
    }
}

추가 예제는 제네릭 컬렉션용 인터페이스의 가변성 사용(C# 및 Visual Basic)을 참조하십시오.

제네릭 인터페이스의 가변성(variance)은 참조 형식에 대해서만 지원됩니다. 값 형식은 가변성(variance)을 지원하지 않습니다. 예를 들어, 정수가 값 형식으로 표시되기 때문에 IEnumerable<int>(Visual Basic의 경우 IEnumerable(Of Integer))을 IEnumerable<object>(Visual Basic의 경우 IEnumerable(Of Object))로 암시적으로 변환할 수 없습니다.

Dim integers As IEnumerable(Of Integer) = New List(Of Integer)
' The following statement generates a compiler error
' with Option Strict On, because Integer is a value type.
' Dim objects As IEnumerable(Of Object) = integers
IEnumerable<int> integers = new List<int>();
// The following statement generates a compiler errror,
// because int is a value type.
// IEnumerable<Object> objects = integers;

variant 인터페이스를 구현하는 클래스는 여전히 invariant입니다. 예를 들어, List<T>이 공변(covariant) 인터페이스 IEnumerable<T>을 구현하지만 List<Object>(Visual Basic의 경우 List(Of Object))를 List<String>(Visual Basic의 경우 List(Of String))로 암시적으로 변환할 수 없습니다. 이에 대한 예는 다음 코드 예제에 나와 있습니다.

' The following statement generates a compiler error
' because classes are invariant.
' Dim list As List(Of Object) = New List(Of String)

' You can use the interface object instead.
Dim listObjects As IEnumerable(Of Object) = New List(Of String)
// The following line generates a compiler error
// because classes are invariant.
// List<Object> list = new List<String>();

// You can use the interface object instead.
IEnumerable<Object> listObjects = new List<String>();

참고 항목

참조

제네릭 컬렉션용 인터페이스의 가변성 사용(C# 및 Visual Basic)

개념

Variant 제네릭 인터페이스 만들기(C# 및 Visual Basic)

제네릭 인터페이스

대리자의 가변성(C# 및 Visual Basic)