다음을 통해 공유


where(제네릭 형식 제약 조건)(C# 참조)

제네릭 정의의 where 절은 제네릭 형식, 메서드, 대리자 또는 로컬 함수의 형식 매개 변수에 대한 인수로 사용되는 형식에 대한 제약 조건을 지정합니다. 제약 조건은 인터페이스, 기본 클래스를 지정하거나 제네릭 형식을 참조, 값 또는 관리되지 않는 형식으로 요구할 수 있습니다. 형식 인수에 있어야 하는 기능을 선언하고, 선언된 기본 클래스 또는 구현된 인터페이스 다음에 배치해야 합니다.

예를 들어 형식 매개 변수 TIComparable<T> 인터페이스를 구현하도록 제네릭 클래스 AGenericClass를 선언할 수 있습니다.

public class AGenericClass<T> where T : IComparable<T> { }

참고

쿼리 식의 where 절에 대한 자세한 내용은 where 절을 참조하세요.

where 절에는 기본 클래스 제약 조건이 포함될 수도 있습니다. 기본 클래스 제약 조건에서는 해당 제네릭 형식에 대한 형식 인수로 사용할 형식이 지정된 클래스를 기본 클래스로 포함하거나 해당 기본 클래스임을 명시합니다. 기본 클래스 제약 조건이 사용되는 경우 해당 형식 매개 변수에 대한 다른 제약 조건 앞에 나타나야 합니다. 일부 형식은 Object, ArrayValueType 기본 클래스 제약 조건으로 허용되지 않습니다. 다음 예제에서는 이제 기본 클래스로 지정할 수 있는 형식을 보여 줍니다.

public class UsingEnum<T> where T : System.Enum { }

public class UsingDelegate<T> where T : System.Delegate { }

public class Multicaster<T> where T : System.MulticastDelegate { }

null 허용 컨텍스트에서는 기본 클래스 형식의 null 허용 여부가 적용됩니다. 기본 클래스가 null을 허용하지 않는 경우(예: Base) 형식 인수는 null을 허용하지 않아야 합니다. 기본 클래스가 null을 허용하는 경우(예: Base?) 형식 인수는 null을 허용하거나 null을 허용하지 않는 참조 형식일 수 있습니다. 기본 클래스가 null을 허용하지 않는 경우 형식 인수가 null 허용 참조 형식이면 컴파일러가 경고를 발생시킵니다.

where 절은 형식이 class 또는 struct임을 지정할 수 있습니다. struct 제약 조건은 System.ValueType의 기본 클래스 제약 조건을 지정할 필요가 없습니다. System.ValueType 형식은 기본 클래스 제약 조건으로 사용할 수 없습니다. 다음 예제에서는 classstruct 제약 조건을 모두 보여 줍니다.

class MyClass<T, U>
    where T : class
    where U : struct
{ }

null 허용 컨텍스트에서 class 제약 조건을 사용하려면 null을 허용하지 않는 참조 형식이 있어야 합니다. null 허용 참조 형식을 허용하려면 null 허용 참조 형식 및 null을 허용하지 않는 참조 형식을 둘 다 허용하는 class? 제약 조건을 사용합니다.

where 절은 notnull 제약 조건을 포함할 수 있습니다. notnull 제약 조건은 형식 매개 변수를 Null을 허용하지 않는 형식으로 제한합니다. 해당 형식은 값 형식이거나 null을 허용하지 않는 참조 형식일 수 있습니다. nullable enable 컨텍스트에서 컴파일된 코드에 대해 notnull 제약 조건을 사용할 수 있습니다. 다른 제약 조건과 달리 형식 인수가 notnull 제약 조건을 위반하면 컴파일러는 오류 대신 경고를 생성합니다. 경고는 nullable enable 컨텍스트에서만 생성됩니다.

nullable 참조 형식 추가로 인해 제네릭 메서드에서 T?의 의미가 모호해질 수 있습니다. Tstruct이면 T?System.Nullable<T>과 같습니다. 그러나 T가 참조 형식이면 T?null이 유효한 값임을 의미합니다. 이 모호성은 재정의 메서드에 제약 조건을 포함할 수 없기 때문에 발생합니다. 새 default 제약 조건을 사용하면 이 모호성이 해결됩니다. 기본 클래스 또는 인터페이스에서 두 개의 메서드 두 오버로드, 즉 struct 제약 조건을 지정하는 오버로드와 struct 또는 class 제약 조건을 적용하지 않은 오버로드를 선언하는 경우 이 제약 조건을 추가합니다.

public abstract class B
{
    public void M<T>(T? item) where T : struct { }
    public abstract void M<T>(T? item);

}

default 제약 조건을 사용하면 파생 클래스에 제약 조건을 사용하지 않거나 명시적 인터페이스 구현 없이 파생 클래스에서 메서드를 재정의하도록 지정할 수 있습니다. 이 제약 조건은 기본 메서드 또는 명시적 인터페이스 구현을 재정의하는 메서드에만 유효합니다.

public class D : B
{
    // Without the "default" constraint, the compiler tries to override the first method in B
    public override void M<T>(T? item) where T : default { }
}

중요

notnull 제약 조건을 포함하는 제네릭 선언은 nullable 형식을 감지하지 않는 컨텍스트에서 사용될 수 있지만 컴파일러는 제약 조건을 적용하지 않습니다.

#nullable enable
    class NotNullContainer<T>
        where T : notnull
    {
    }
#nullable restore

where 절에 unmanaged 제약 조건이 포함될 수도 있습니다. unmanaged 제약 조건은 형식 매개 변수를 관리되지 않는 형식으로 알려진 형식으로 제한합니다. unmanaged 제약 조건을 사용하면 C#에서 하위 수준의 interop 코드를 더 쉽게 작성할 수 있습니다. 이 제약 조건을 통해 모든 관리되지 않는 형식에서 재사용 가능한 루틴을 사용할 수 있습니다. unmanaged 제약 조건은 class 또는 struct 제약 조건과 결합할 수 없습니다. unmanaged 제약 조건에 따라 형식이 struct이어야 합니다.

class UnManagedWrapper<T>
    where T : unmanaged
{ }

where 절에 new() 생성자 제약 조건이 포함될 수도 있습니다. 이 제약 조건을 사용하면 new 연산자를 사용하여 형식 매개 변수의 인스턴스를 만들 수 있습니다. new () 제약 조건을 사용하면 컴파일러에서 제공된 형식 인수에 액세스 가능하고 매개 변수가 없는 생성자가 있어야 한다는 것을 알게 됩니다. 예를 들어:

public class MyGenericClass<T> where T : IComparable<T>, new()
{
    // The following line is not possible without new() constraint:
    T item = new T();
}

new() 제약 조건은 where 절 맨 끝에 나타납니다. new() 제약 조건은 struct 또는 unmanaged 제약 조건과 결합할 수 없습니다. 이러한 제약 조건을 충족하는 모든 형식에는 매개 변수가 없는 액세스 가능 생성자가 있어야 하므로 new() 제약 조건이 중복됩니다.

형식 매개 변수가 여러 개이면 각 형식 매개 변수에 하나의 where 절을 사용합니다. 예를 들면 다음과 같습니다.

public interface IMyInterface { }

namespace CodeExample
{
    class Dictionary<TKey, TVal>
        where TKey : IComparable<TKey>
        where TVal : IMyInterface
    {
        public void Add(TKey key, TVal val) { }
    }
}

다음 예제와 같이 제약 조건은 제네릭 메서드의 형식 매개 변수에 연결할 수도 있습니다.

public void MyMethod<T>(T t) where T : IMyInterface { }

대리자에 대한 형식 매개 변수 제약 조건을 설명하는 구문은 메서드의 구문과 동일합니다.

delegate T MyDelegate<T>() where T : new();

제네릭 대리자에 대한 자세한 내용은 제네릭 대리자를 참조하세요.

제약 조건의 구문 및 사용에 대한 자세한 내용은 형식 매개 변수에 대한 제약 조건을 참조하세요.

C# 언어 사양

자세한 내용은 C# 언어 사양을 참조하세요. 언어 사양은 C# 구문 및 사용법에 대 한 신뢰할 수 있는 소스 됩니다.

참고 항목