개발공부/C#

[Effective C#] 아이템 22 : 공변성과 반공변성을 지원하라

개발자 찐빵이 2021. 11. 28. 20:26
728x90

공변과 반공변

특정 타입의 객체를 다른 타입의 객체로 변환할 수 있는 성격.
공변 : X를 Y로 바꿔 사용할 수 있는 경우, C<X>를 C<Y>로 바꾸는 것이 가능하면 C<T>는 공변이다.
반공변 : Y를 X로 바꿔 사용할 수 있는 경우, C<X>를 C<Y>로 바꾸는 것이 가능하면 C<T>는 반공변이다.

공변성과 반공변성은 가변성(variance)라고 부른다. ↔ 불변성(invariant)

변환 지원 방법

제네릭 인터페이스나 델리게이트의 정의 부분에 데코레이터를 추가해야 한다.
데코레이터 : 제네릭 공변/반공변을 지원한다는 의미

제네릭 타입에 대한 공변

공변과 반공변을 지원하는 in, out 키워드.
이 데코레이터는 주로 제네릭 인터페이스나 델리게이트 선언 시에 사용할 수 있다.

public static void CovariantGeneric(IEnumerable<CelestialBody> baseItems)
{
    foreach (var thing in baseItems)
        Console.WriteLine("{0} has a mass of {1} Kg",
            thing.Name, thing.Mass);
}

public interface IEnumerable<out T> : IEnumerable //출력 위치에서만 타입 매개변수를 사용하겠다.
{
    new IEnumerator<T> GetEnumerator();
}

public interface IEnumerator<out T> : IDisposable, IEnumerator
{
    new T Current { get; }
    // MoveNext(), Reset()은 IEnumerator에서 상속받음.
}

설명

IEnumerable를 정의할 때, T를 out으로 선언했기 때문에 CovariantGeneric 메서드에서 List 타입인 baseItems 객체를 인자로 전달할 수 있다.

out 데코레이터의 역할

타입 매개변수 T를 출력 위치에서만 사용하겠다고 컴파일러에게 알려준다.
(출력 위치 : 함수의 반환값, 속성의 get 접근자, 델리게이트의 일부 위치)
out 키워드를 선언하면 컴파일러는 시퀀스 내에서 T를 조회하지만 수정하지 않을 것이라고 생각한다.

제네릭 타입에 대한 반공변

out을 in으로만 바꾸면, 반공변을 사용할 수 있다.

in 데코레이터의 역할

컴파일러에게 타입 매개변수를 입력 위치에서만 사용할 것이라고 알려준다.
(입력 위치 : 메서드의 매개변수, 일부 델리게이트의 매개변수를 지정하는 용도)

델리게이트 매개변수에 대한 공변과 반공변

메서드의 매개변수 타입은 반공변(in)이고 반환 타입이 공변(out)이다.

결론

  • 공변과 반공변이 어떻게 동작하는지는 정확하게 설명하기 어렵지만, 제네릭 인터페이스나 델리게이트 정의 시에 사용할 수 있는 in(반공변), out(공변) 데코레이터가 있다.
  • 가능하면 제네릭 인터페이스나 델리게이트 정의 시에 in, out 데코레이터를 사용하자.
    가변성과 관련된 에러를 컴파일러가 사전에 확인할 수 있다.
반응형