[C# 4.0] Generic Covariance And Contra Variance

C# 2009. 4. 13. 20:22 Posted by 알 수 없는 사용자
처음에 이 용어를 보고 정확하게 무슨 뜻인지 잘 몰랐습니다.
그래서 이곳 저곳 검색해 본 결과, 좋은 예제를 하나 소개해 드립니다.
참고 : http://playdotnet.spaces.live.com/blog/cns!7F811570C85CF4EA!4600.entry
public class Employee { }
public class Manager:Employee { }

Employee employee = new Employee();
Manager manager = new Manager();
//Covariance.
Employee manager = new Manager(); 
위 예제의 마지막 코드를 보면 Manager 타입의 객체가 Employee 타입의 Manager 변수로 대입 되었습니다. 생각해 보건대, 매니져도 월급을 받는 직원이므로 당연한 것이지만, 프로그래밍 세계에서는 이것을 Covariance 로 부르더군요. 저도 알게 모르게 이런 코드를 많이 사용했었습니다.

그럼 이건 어떤가요?
public void GetSalary(Employee employee) { }
Employee employee = new Employee();
GetSalary(employee);
Manager manager = new Manager();

//Contra variance.
GetSalary(manager);
이번 코드에서는 직원에 월급을 주고 있습니다. 매니져도 직원이므로 월급을 주는 것이 당연합니다. 이런 경우를 Contra Variance라 하네요. 참 재미있는 용어들입니다. 언뜻 생각하면 참 당연한 말인데요. ^^;  
참 그리고 보니, InVariance 도 있습니다.
//AppointNewManager() 는 Manager 타입의 변수를 return 합니다.
Product product = AppointNewManager();
새로운 매니저를 제품으로 볼 수는 없지요. 가끔 그러고 싶은 생각도 있습니다. ㅋㅋㅋ

C# 버젼 별로 variance의 의미를 종합해 보면은요,

Variance in Arrays (C# 1.0)

Value 타입의 Integer 타입의 Array는 당연히 Double Type의 변수를 Element로 사용할 수 없습니다. Invariance 합니다. 
Int32[] numbers = new Double[3];
 
Reference 타입의 경우 아래  코드는 Covariance합니다. 단 매니져가 직원이어야 합니다., 쉽게 말하면 매니져의 부모 타입이 Employee 이지요, 근데 가끔 프리랜서도 있을수 있으므로 주의!
Employee[] employees = new Manager[3];
  
public class Animal { }
public class Lion:Animal { }
Animal[] animals = new Lion[3];
 
위 예제는 Covariance 하지만, 만약 이런경우에는 
  
public class Deer Animal }
Animal[] animals = new Lion[3];
animals[0] = new Deer();

동물에 사자도 들어 갈수 있고, 사슴도 가능하지만(Covariance), 실제 코드에서는 문제가 발생할 수 있습니다.  animals array 가 사자 우리라고 생각한다면, 들어간 사슴은 잡아 먹히겠지요. T.T

Variance in Delegate-Member Association (C# 2.0)
 
Func<Employee> generateEmployee = AppointNewManager;
Action<Manager> salaryAction = GetSalary;
 
Delegate Func<T> 는 인자는 없고, return type은 타입 T입니다. 
AppointNewManager는 Manager 타입을 return 하고 Manager 타입의 부모는  당연히 employee입니다. 즉 Covariance 합니다
 
Delegate Action<T> 는 타입 T의 변수를 인자로 받고, return 값은 없습니다.
GetSalary는 Manager 타입의 변수를 인자로 받는데, 이것 역시 매니져는 직원이므로 월급을 받을 수 있고, 아까 전에 언급한대로 Contra Variance라 부릅니다.

Variance in Generic Delegate (C# 3.0)
 
Func<Manager> generateManager = AppointNewManager;
Func<Employee> generateEmployee = genrateManager;

Action<Employee> salaryAction = GetSalary;
Action<Manager> salary = salaryAction;
 
C# 2.0 예제와는 달리 이 예제들은 Invariance 합니다. Generic delegate에 대해서는 compile error가 발생합니다. Generic 의 업격한 타입 검사가 이런 문제는 발생시키는 건가요? 
C# 4.0 에서는 이런 문제를 해결하기 위해 Generic Covariance And Contra Variance 가 등장합니다.

Variance for Generic Delegates (C# 4.0)

Covariance 를 지원하려면. OUT 
public delegate Func1<out T>();
 
Func1<Manager> generateManager = AppointNewManager;
Func1<Employee> generateEmployee = generateManager;
 
Contra Variance 의 경우는 IN
public delegate void Action1<in T>(T a);
Action1<Employee> salaryAction = GetSalary;
Action1<Manager> salary = salaryAction;

약 처음부터 이 부분을 보셨다면, C#에 익숙하지 않은 저 같은 사람은 이해 하기 가 많이 어려웠을겁니다. 그래서 공부하면서 정리한 내용과 함꼐,  가장 쉽다고 생각한 블로그에서 인용 한 것인데,  제가 잘 이해했는지 모르겠네요.  말로 설명하는 것 보다, 하나의 구체적인 예를 들고 적용해 보면 더 확실히 의미가 다가올 것 같습니다. 제 노트북에서는 Virtual PC 돌아가는 것도 상당히 버거워서 실제 컴파일은 해 보지도 못 했답니다. 양해부탁드립니다. 





'C#' 카테고리의 다른 글

Welcome to Dynamic C#(2) - Wanna be a polyglot.  (2) 2009.05.17
Welcome to Dynamic C#(1) - 첫만남.  (1) 2009.05.04
[C# 4.0] New Extension Method “Zip”  (1) 2009.04.08
[C# 4.0] Duck Typing  (6) 2009.04.06
[C# 4.0] Named and Optional Parameters  (1) 2009.04.06