형식 매개 변수를 제한하면, 허용되는 작업의 수 및 제한하는 형식과 해당 상속 계층 구조의 모든 형식에서 지원하는 메서드에 대해 허용되는 호출의 수를 늘릴 수 있습니다. 따라서 제네릭 클래스나 메서드를 디자인할 때 System.Object에서 지원하지 않는 메서드를 호출하거나 제네릭 멤버에 대해 단순한 할당 이상의 작업을 수행하려는 경우에는 형식 매개 변수에 제약 조건을 적용해야 합니다.
where T : class 제약 조건을 적용할 때는 형식 매개 변수에 대해 == 및 != 연산자를 사용하지 않는 것이 좋습니다. 이러한 연산자에서는 값이 같은지 확인하는 대신 참조가 동일한지만 테스트하기 때문입니다. 인수로 사용되는 형식에서 이러한 연산자를 오버로드한 경우에도 마찬가지입니다. 다음 코드에서는 이러한 경우의 예를 보여 줍니다. String 클래스에서 == 연산자를 오버로드해도 false가 출력됩니다.
C# 코드 복사
public static void OpTest<T>(T s, T t) where T : class
{
System.Console.WriteLine(s == t);
}
static void Main()
{
string s1 = "foo";
System.Text.StringBuilder sb = new System.Text.StringBuilder("foo");
string s2 = sb.ToString();
OpTest<string>(s1, s2);
}
이러한 방식으로 동작하는 이유는 컴파일 시 컴파일러에는 T가 참조 형식이라는 정보만 제공되므로 모든 참조 형식에 유효한 기본 연산자가 사용되기 때문입니다. 값이 동일한지 테스트하려면 where T : IComparable<T>제약 조건을 함께 적용하고 제네릭 클래스를 생성하는 데 사용되는 모든 클래스에서 해당 인터페이스를 구현하는 것이 좋습니다.
바인딩되지 않은 형식 매개 변수
공용 클래스 SampleClass<T>{}의 T와 같이 제약 조건이 없는 형식 매개 변수를 바인딩되지 않은 형식 매개 변수라고 합니다. 바인딩되지 않은 형식 매개 변수에는 다음과 같은 규칙이 적용됩니다.
!= 및 == 연산자를 사용할 수 없습니다. 구체적인 형식 인수에서 이러한 연산자를 지원하리라는 보장이 없기 때문입니다.
바인딩되지 않은 형식 매개 변수와 System.Object 사이에 변환하거나 이 매개 변수를 임의의 인터페이스 형식으로 명시적으로 변환할 수 있습니다.
바인딩되지 않은 형식 매개 변수를 null과 비교할 수 있습니다. 바인딩되지 않은 매개 변수를 null과 비교하는 경우 형식 인수가 값 형식이면 비교 결과로 항상 false가 반환됩니다.
naked 형식 제약 조건
제네릭 형식 매개 변수를 제약 조건으로 사용하는 경우 이를 naked 형식 제약 조건이라고 합니다. naked 형식 제약 조건은 다음 예제에서와 같이 자체 형식 매개 변수가 있는 멤버 함수에서 해당 매개 변수를 포함 형식의 형식 매개 변수로 제한해야 하는 경우에 유용합니다.
C# 코드 복사
class List<T>
{
void Add<U>(List<U> items) where U : T {/*...*/}
}
위 예제에서 T는 Add 메서드의 컨텍스트에서는 naked 형식 제약 조건이고 List 클래스의 컨텍스트에서는 바인딩되지 않은 형식 매개 변수입니다.
naked 형식 제약 조건은 제네릭 클래스 정의에도 사용할 수 있습니다. naked 형식 제약 조건도 다른 모든 형식 매개 변수와 마찬가지로 꺾쇠괄호 안에 선언해야 합니다.
C# 코드 복사
//naked type constraint
public class SampleClass<T, U, V> where T : V { }
컴파일러에서는 naked 형식 제약 조건이 System.Object에서 파생된다는 점을 제외하고는 이 제약 조건에 대해 어떠한 정보도 알 수 없으므로 naked 형식 제약 조건과 제네릭 클래스를 함께 사용할 필요는 거의 없습니다. 제네릭 클래스에 대해 naked 형식 제약 조건을 사용하는 경우로는 두 형식 매개 변수 사이에 반드시 상속 관계가 있도록 정의하는 경우를 들 수 있습니다.