17. 제네릭 가변성(공변 out / 반공변 in)과 배열 공변성의 차이
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 주제: 제네릭 가변성(variance) — 인터페이스 공변(out)/반공변(in) 과 배열 공변성의 차이.
//
// IEnumerable<out T> 는 공변, Action<in T> 는 반공변이다. 반면 List<T> 는 불변(invariant)이고,
// 배열은 (역사적 이유로) 공변이지만 그 공변은 타입 안전하지 않다.
//
// 과제:
// 1) 이 프로그램의 정확한 표준출력을 예측하라(네 줄).
// 2) (1) 공변, (2) 반공변 대입이 각각 왜 컴파일되는지(out/in 의 의미)를 설명하라.
// 3) (3) 배열 공변성은 왜 컴파일은 되는데 런타임 예외가 나는지, 인터페이스 공변성과
// 무엇이 다른지 설명하라.
// 4) 주석 처리된 List<Animal> 대입이 왜 컴파일 에러인지(List<T> 가 불변인 이유) 설명하라.
using System;
using System.Collections.Generic;
class Animal { public virtual string Name => "Animal"; }
class Cat : Animal { public override string Name => "Cat"; }
class Program
{
static void PrintAll(IEnumerable<Animal> animals)
{
foreach (var a in animals) Console.Write(a.Name + " ");
Console.WriteLine();
}
static void Main()
{
// (1) 인터페이스 공변성: IEnumerable<out T>
List<Cat> cats = new List<Cat> { new Cat(), new Cat() };
IEnumerable<Animal> asAnimals = cats;
PrintAll(asAnimals);
// (2) 인터페이스 반공변성: Action<in T>
Action<Animal> printAnimal = a => Console.WriteLine("animal " + a.Name);
Action<Cat> assigned = printAnimal;
assigned(new Cat());
// (3) 배열 공변성(불안전)
Animal[] arr = new Cat[2];
try
{
arr[0] = new Animal();
Console.WriteLine("stored Animal");
}
catch (ArrayTypeMismatchException)
{
Console.WriteLine("ArrayTypeMismatchException");
}
// (4) List<T> 는 불변: 아래는 컴파일 에러라 주석 처리
// List<Animal> bad = cats; // CS0266
Console.WriteLine("done");
}
} 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.