본문 바로가기

프로그래밍 언어 노트/C#

[C#] 공변성(Covariance)과 반 공변성(Contravariance )

객체지향의 원칙중 하나인 LSP (리스코프 치환 원칙) 의 위키백과에는 아래와 같은 내용이 존재한다.

리스코프의 원칙은 새로운 객체 지향 프로그래밍 언어에 채용된 시그니처에 관한 몇 가지 표준적인 요구사항을 강제한다.

  • 하위형에서 메서드 인수의 반공변성
  • 하위형에서 반환형의 공변성
  • 하위형에서 메서드는 상위형 메서드에서 던져진 예외의 하위형을 제외하고 새로운 예외를 던지면 안된다.

핵심단어는 공변성과 반공변성이다.

 

공변성(Covariance)

Animal 클래스를 상속받은 Dog 클래스가 있다.
Animal 과 Dog은 상속관계이므로

Animal animal = new Dog();

이 가능하다.

그럼

IEnumerable<Animal> animals = new List<Dog>();

은 가능할까?

정답은 가능하다. 그리고 자연스럽게 위처럼 프로그래밍한적이 있었을것이다.

그런데 이것이 어떻게 가능한것일까? 우리가 상속 관계를 표현한것은 Animal 과 Dog 이지 IEnumerable<Animal> 과의 관계가 아니다.

이것을 가능한 이유는 IEnumerable 인터페이스는  공변성 을 가지고 있기 때문이다.

X -> Y일때 C<T>가 C<X> -> C<Y>라면 공변이다.

C# 에서는 Generic 을 사용할때 out키워드를 붙여주는것으로 공변이라는것을 알려준다.

public interface IEnumerable<[NullableAttribute(2)] out T> : IEnumerable
{
    ///
}

IEnumerable 타입에의 T 앞에 out 키워드가 있는것을 확인할수있다.

 

반공변성 (Contravariance)

X -> Y일때 C<T>가 C<X> -> C<Y> 가 공변이라면 반공변은 반대로

X -> Y일때 C<T>가 C<Y> -> C<X> 이다.

공변성이야 자식관계과 인터페이스 동일하게 에서도 적용된다는 느낌으로 이해가 된다.

그런대 반공변성은 쉽게 이해가 되지 않는다. 반공변성은 왜 필요한것일까?

위에서 확인할수 있듯이 Action 델리게이터의 경우 반공변으로 선언되어있다.

Animal 이 할수있는 함수의 경우 Dog 이 할수있을까? 할수있다. Animal을 상속받았으니까
-> 즉 Play(Animal animal) 에 Play(dog) 이 가능하다.

Dog 이 할수있는일을 Animal이 할수있을까? 할수없다. 뭔지 모르기 때문이다.
-> 즉 Play(Dog dog) 에 Play(animal) 은 불가능하다.

static Action<Dog> GetPlayDogAction ()
{
    return (d) => d.Play();
}

static Action<Animal> GetPlayAnimalAction()
{
    return (a) => a.Play();
}

static void Main(string[] args)
{
    Animal ani = new Animal();
    Dog dog = new Dog();

    Action<Animal> playAnimalActionToAnimal = GetPlayAnimalAction();
    Action<Dog> playAnimalActionToDog = playAnimalActionToAnimal;

    Action<Dog> playDogActionToDog = GetPlayDogAction();
    //Action<Animal> playDogActionToAnimal = playDog;    //Error

    playAnimalActionToAnimal(ani);
    playAnimalActionToDog(dog);
    playDogActionToDog(dog);

}

즉 Action<Dog> 에 Action<Animal> 을 넣는것은 가능하다.

그러나 Action<Animal> 에 Action<Dog> 을 넣는것은 불가능하다.

IEnumerable<Animal> 에 new List<Dog> 을 넣는것과정 반대의 상황이다.

이를 반공변이라고 한다.

 

 

반공변과 공변의 훌륳한 시각화 자료..

 

728x90