where - Generics (type parameter, 형식 제약 조건)
제네릭 클래스를 정의하는 경우 클래스를 인스턴스화할 때 클라이언트 코드에서 형식 인수에 사용할 수 있는 형식의 종류에 제약 조건을 적용할 수 있습니다.
클라이언트 코드가 제약 조건에서 허용하지 않는 형식을 사용하여 클래스를 인스턴스화하려고 하면 컴파일 타임 오류가 발생합니다.
이러한 제한을 제약 조건이라고 합니다. 제약 조건은 컨텍스트 키워드 where를 사용하여 지정합니다. 다음 표에서는 여섯 가지의 형식 제약 조건을 보여 줍니다.
제네릭 형식 정의에서 where 절은 제네릭 선언에 정의된 형식 매개 변수의 인수로 사용할 수 있는 형식에 대해 제약 조건을 지정하는 데 사용됩니다.
기본적으로 형식 제약을 하지 않는 다면, C++의 Template와 매우 흡사하게 사용할 수 있습니다.
Generics 메소드
static void Print<T>(T _value)
{
string msg = string.Empty;
if (_value.GetType() == typeof(int))
msg = "int 형";
else if (_value.GetType() == typeof(float))
msg = "float 형";
else if (_value.GetType() == typeof(bool))
msg = "bool 형";
Console.WriteLine(msg + "자료 입니다.");
}
static void Main(string[] args)
{
int value1 = 10;
float value2 = 1.5f;
bool value3 = false;
Print(value1);
Print(value2);
Print(value3);
}
//--
//int 형자료 입니다.
//float 형자료 입니다.
//bool 형자료 입니다.
다음과 같이 여러개의 형식을 사용 할 수도 있습니다.
static void Print<T , U>(T _value , U _value2)
{
string msg = string.Empty;
string msg2 = string.Empty;
if (_value.GetType() == typeof(int))
msg = "int 형";
if (_value2.GetType() == typeof(float))
msg2 = "float 형";
Console.WriteLine(msg + "와 " + msg2 + "자료 입니다.");
}
static void Main(string[] args)
{
int value1 = 10;
float value2 = 1.5f;
Print(value1 , value2);
}
//--결과
//int 형와 float 형자료 입니다.
Generics 클래스
다음은 LIST를 간략하게 구현한 클래스입니다.
public class GenericList<T>
{
private T[] arr;
private int count;
public GenericList()
{
arr = new T[10];
count = 0;
}
public void Add(T input)
{
arr[count++] = input;
}
public void Print(int _index)
{
Console.WriteLine(arr[_index]);
}
public void PrintAll()
{
foreach(var data in arr)
{
Console.WriteLine(data);
}
}
}
static void Main(string[] args)
{
GenericList<int> numbers = new GenericList<int>();
for (int i = 0; i < 10; i++ )
{
numbers.Add(i);
}
numbers.PrintAll();
}
//-- 결과
// 0,1,2,3,4,5,6,7,8,9
형식 제약 where
제너릭에서 형식을 제약하려면 where 키워드를 사용합니다.
제네릭 목록의 항목을 검사하여 그 유효성 여부를 확인하거나 이 항목을 다른 항목과 비교하려는 경우,
컴파일러는 클라이언트 코드에서 지정할 수 있는 모든 형식 인수에 대해 호출해야 할 메서드나 연산자가 지원되는지 확인해야 합니다.
하나 이상의 제약 조건을 제네릭 클래스 정의에 적용하면 이러한 확인이 가능합니다.
예를 들어, 기본 클래스 제약 조건에서는 이 형식의 개체와 이 형식에서 파생된 개체만이 형식 인수로 사용될 수 있음을 컴파일러에 알립니다.
컴파일러에서 이를 확인하면 사용자는 제네릭 클래스에서 해당 형식의 메서드를 호출할 수 있습니다.
제약 조건은 컨텍스트 키워드 where를 사용하여 적용됩니다.
where T: struct - 형식 인수가 값 형식이어야 합니다. Nullable를 제외한 임의의 값 형식을 지정할 수 있습니다.
where T : class - 형식 인수가 참조 형식이어야 합니다. 이는 모든 클래스, 인터페이스, 대리자 또는 배열 형식에도 적용됩니다.
where T : new() - 형식 인수가 매개 변수 없는 공용 생성자를 가지고 있어야 합니다. 다른 제약 조건과 함께 사용하는 경우 new() 제약 조건은 마지막에 지정해야 합니다.
where T : <기본 클래스 이름> - 형식 인수가 지정된 기본 클래스이거나 지정된 기본 클래스에서 파생되어야 합니다.
where T : <인터페이스 이름> - 형식 인수가 지정된 인터페이스이거나 지정된 인터페이스를 구현해야 합니다. 여러 인터페이스 제약 조건을 지정할 수 있습니다. 제한하는 인터페이스는 제네릭이 될 수도 있습니다.
where T : U - T에 대해 지정한 형식 인수가 U에 대해 지정한 인수이거나 이 인수에서 파생되어야 합니다.
public class GenerisClass<T> where T: class {}
public class GenerisStruct<T> where T : struct { }
public class GenerisClass2<T> where T : class , new () { }
public class GenerisClass3<T> where T : Test2 { }
public class Test {}
public class Test2 { }
static void Main(string[] args)
{
GenerisClass<Test> generisClass = new GenerisClass<Test>();
GenerisClass2<Test> generisClass2 = new GenerisClass2<Test>();
GenerisClass3<Test2> generisClass3 = new GenerisClass3<Test2>();
GenerisStruct<int> generisStruct = new GenerisStruct<int>();
}
다음과 같이 여러개의 제약조건을 동시에 지정할 수 있습니다.
public class GenerisClass<T> where T : class , System.IComparable, new() { }
public class Test : System.IComparable { }
static void Main(string[] args)
{
GenerisClass<Test> generisClass = new GenerisClass<Test>();
}
바인딩되지 않은 형식 매개 변수
공용 클래스 SampleClass<T>{}의 T와 같이 제약 조건이 없는 형식 매개 변수를 바인딩되지 않은 형식 매개 변수라고 합니다. 바인딩되지 않은 형식 매개 변수에는 다음과 같은 규칙이 적용됩니다. != 및 == 연산자를 사용할 수 없습니다.
체적인 형식 인수에서 이러한 연산자를 지원하리라는 보장이 없기 때문입니다.
바인딩되지 않은 형식 매개 변수와 System.Object 사이에 변환하거나 이 매개 변수를 임의의 인터페이스 형식으로 명시적으로 변환할 수 있습니다.
바인딩되지 않은 형식 매개 변수를 null과 비교할 수 있습니다. 바인딩되지 않은 매개 변수를 null과 비교하는 경우 형식 인수가 값 형식이면 비교 결과로 항상 false가 반환됩니다.
제약조건으로서의 형식 매개 변수
일반 형식을 제약 조건으로 사용하면 다음 예제에서와 같이 자체 형식 매개 변수가 있는 멤버 함수에서 해당 매개 변수를 포함 형식의 형식 매개 변수로 제한해야 하는 경우에 유용합니다.
class List<T>
{
public readonly int numebr;
public List() { }
public List(int _num)
{
numebr = _num;
}
public void Add<U>(List<U> items) where U : T
{
Console.WriteLine(items.numebr);
}
}
static void Main(string[] args)
{
List<int> list = new List<int>();
List<int> list2 = new List<int>(10);
list.Add(list2);
}
[참고]
where(제네릭 형식 제약 조건)
- https://msdn.microsoft.com/ko-kr/library/bb384067.aspx
형식 매개 변수에 대한 제약 조건
- https://msdn.microsoft.com/ko-kr/library/d5x73970.aspx
'프로그래밍 > C#' 카테고리의 다른 글
[C#] Serialization - 객체 직렬화 (0) | 2016.10.29 |
---|---|
[C#] yield 키워드 (0) | 2016.10.29 |
[C#] 무명 메서드(Anonymous Methods) (0) | 2016.09.29 |
[C#] IEnumerable , IEnumerator 인터페이스 (0) | 2016.09.29 |
[C#] 람다식 (lambda) - 1 (0) | 2016.09.25 |