1편에 이어서 제네릭의 타입제한 및 BCL에 적용된 제네릭에 대해서 정리하겠다. 시작 하기전에 앞서 앞서 배운 내용을 정리하자면, 제네릭이 도입 되기전에는 Object 형식의 배열 형태로 다양한 타입을 입력 받아 관리 하였으나, 박싱/언박싱 문제로 비효율적인 메모리 사용 문제가 발생하였고 이 문제를 해결하기위해 다양한 타입의 함수를 작성하여 처리하였으나, 중복의 문제가 발생하였다. 이러한 문제를 해결하기 위한 방법으로 제네릭을 사용한다. 제네릭 타입의로 지정 시
CLR은 JIT 컴파일 시에 클래스가 타입에 따라 정의 될때마다 T에 대응되는 타입을 대체해서 확장한다. 즉 매개변수 전달 타입에 따라 N개의 클래스에 해당하는 기계어 코드가 자동으로 만들어 진다는 뜻이다.
정리하자면 제네릭의 사용은 박싱/언박싱으로 발생하는 비효율적인 힙 메모리 사용 문제를 없앨뿐더러 데이터 타입에 따른 코드 중복 문제도 해결해 준다.
형식 매개변수에 대한 제약 조건
제네릭을 사용하다 보면 형식 매개변수로 받아들이는 타입이 특정 조건을 만족해야만 할 때가 있다.
해당 코드를 사용하면 T에 CompareTo 에 대한 정의가 없고 T 형식의 첫번째 인수를 허용하는 확장 메서드
CompareTo 가 없습니다. 라는 오류가 발생한다. T로 대체하는 타입이 모두 CompareTo를 지원하는게
아니므로 컴파일 단계에서 오류를 발생시켜 잘못된 사용을 막는 것이다. 바로 이런 경우에
T에 입력될수 있는 타입의 조건 Where 예약어를 사용해 제한 할 수 있다.
where 예약어 다음에 형식 매개변수를 지정하고 콜론(:) 구분자로 사용해 제약 조건을 걸 수 있다.
컴파일러는 IComparable 인터페이스를 상속 받은 타입의 인스턴스라고 가정하게 되고 코드에서
Comparto 메서드를 호출하는것을 허용한다.
추가적 으로 지원하는 제약 조건 이다.
where T : struct 값 형식만 가능하다.
where T : class 참조 형식만 가능하다.
where T : new() 매개변수 없는 공용 생성자가 포함돼 있어야 한다.
where T : U U형식 인수에 해당하는 타입이거나 그것으로부터 상속 받은 클래스만 가능하다.
해당 코드를 실행하면 값 형식의 바이트 크기를 반환하는 코드이다. 제약조건이 없고 값 형식이 아닌 참조형식
을 전달한다면 컴파일시에는 문제 없이 동작하나 실행시에는 오류가 발생할 것이다.
실행 시간에 오류를 발생 시키는 것보다 컴파일 타임에서 오류를 찾을 수 있다면, 훨씬 빠르고 쉽게
오류를 찾아 낼 수 있다.
두번째 예제는 해당 값이 null 인지 아닌지 확인하는 코드이다. 모든 값 형식은 null 상태를 갖지 않으므로
참조 형식에 적용하는게 올바르기 때문에 class 제약조건을 걸어 사용한다.
마무리
요번 내용을 정리하자면 제네릭은 컴파일 타임이 아니라 매개변수가 전달될때 그 값이 결정된다.
이말은 즉슨 위와같이 값 형식의 null을 검사하거나, 특정 형식만 지원하는 함수가 내부에서 동작할 경우에
컴파일 시에는 문제 없이 동작하나 실행 시 문제가 발생할 여지가 있다는 것이다. 제약조건을 명시하므로써
에러가 발생하는 부분을 컴파일 시부터 확인하여 손 쉽게 에러 핸들링을 할 수 있다.
'프로그래밍 > C# .NET' 카테고리의 다른 글
세션 유휴 타이머 (0) | 2025.04.10 |
---|---|
제네릭 (0) | 2023.04.16 |
C# Invoke, BeginInvoke (0) | 2023.04.02 |
다양한 로그 수집 하기 (0) | 2023.03.27 |
BCL (1) (0) | 2023.03.25 |