out
out (제네릭 한정자) (C# 참조)
제네릭 형식 매개변수에 out 키워드를 붙이면 그 형식 매개변수가 공변(covariant) 하다고 선언하는 거예요. out은 제네릭 인터페이스와 델리게이트에서 사용합니다.
공변성 덕분에 제네릭 매개변수가 지정한 형식보다 더 파생된 형식을 쓸 수 있어요. 이 특징이 가능하게 하는 건, 공변 인터페이스를 구현하는 클래스의 암시적 변환과 델리게이트 형식의 암시적 변환이죠. 공변과 반공변 모두 참조 형식은 지원하지만, 값 형식은 지원하지 않아요.
공변 형식 매개변수를 가진 인터페이스의 메서드는, 매개변수가 지정한 형식보다 더 파생된 형식을 반환할 수 있습니다. 예를 들어 .NET에서 System.Collections.Generic.IEnumerable<T>의 형식 T는 공변이라서, 특별한 변환 메서드 없이도 IEnumerable<string> 형식의 개체를 IEnumerable<object> 형식의 개체에 할당할 수 있어요.
공변 델리게이트는 같은 형식이면서 더 파생된 제네릭 형식 매개변수를 가진 다른 델리게이트에 할당할 수 있습니다.
본문
C# 언어 참조 문서는 가장 최근에 릴리스된 C# 언어 버전을 다룹니다. 다가오는 릴리스에 대한 공개 미리 보기(preview) 기능의 초기 문서도 포함하고 있구요. 이 문서는 지난 세 개 버전에서 처음 도입된 기능이나 현재 공개 미리 보기에 있는 기능을 표시해 둡니다. 특정 기능이 C#에서 처음 등장한 시점을 찾고 싶다면 C# 언어 버전 기록 문서를 참고하면 돼요.
공변 제네릭 인터페이스를 선언하고, 확장하고, 구현하는 코드를 볼게요. 그리고 공변 인터페이스를 구현한 클래스에 대해 암시적 변환이 어떻게 일어나는지도 확인해 봅니다.
// Covariant interface.
interface ICovariant<out R> { }
// Extending covariant interface.
interface IExtCovariant<out R> : ICovariant<R> { }
// Implementing covariant interface.
class Sample<R> : ICovariant<R> { }
class Program
{
static void Test()
{
ICovariant<Object> iobj = new Sample<Object>();
ICovariant<String> istr = new Sample<String>();
// You can assign istr to iobj because
// the ICovariant interface is covariant.
iobj = istr;
}
}
제네릭 인터페이스에서 형식 매개변수를 공변으로 선언하려면 아래 조건을 모두 만족해야 해요.
-
해당 형식 매개변수를 인터페이스 메서드의 반환 형식으로만 쓰고, 메서드 인수의 형식으로는 쓰지 않아야 합니다.
[!NOTE] 이 규칙에는 예외가 하나 있어요. 공변 인터페이스가 반공변(contravariant) 제네릭 델리게이트를 메서드 매개변수로 가진다면, 그 델리게이트의 제네릭 형식 매개변수로는 공변 형식을 쓸 수 있어요. 공변·반공변 제네릭 델리게이트에 대한 자세한 내용은 델리게이트의 가변성과 Func 및 Action 제네릭 델리게이트에 가변성 사용을 참고하세요.
-
해당 형식 매개변수를 인터페이스 메서드의 제네릭 제약 조건으로는 쓰지 않아야 합니다.
다음 코드는 공변 제네릭 델리게이트를 선언하고, 인스턴스화하고, 호출하는 방법을 보여줘요. 델리게이트 형식의 암시적 변환도 함께 확인해 봅니다.
// Covariant delegate.
public delegate R DCovariant<out R>();
// Methods that match the delegate signature.
public static Control SampleControl()
{ return new Control(); }
public static Button SampleButton()
{ return new Button(); }
public void Test()
{
// Instantiate the delegates with the methods.
DCovariant<Control> dControl = SampleControl;
DCovariant<Button> dButton = SampleButton;
// You can assign dButton to dControl
// because the DCovariant delegate is covariant.
dControl = dButton;
// Invoke the delegate.
dControl();
}
제네릭 델리게이트에서는 형식 매개변수를 메서드 반환 형식으로만 쓰고 메서드 인수로는 쓰지 않는다면, 그 형식을 공변으로 선언할 수 있습니다.
C# 언어 사양
자세한 내용은 C# 언어 사양을 참고하세요. 언어 사양은 C# 구문과 사용법에 대한 권위 있는 출처입니다.