[C#] 제네릭 클래스

근처야·2025년 2월 27일

C#

목록 보기
3/3

일반적인 클래스는 정의할 때 타입이 고정된다. 예를 들어, 클래스 MyClass를 만들면 int MyClass, string MyClass 같은 변형을 만들 수 없다. 하지만 제네릭을 사용하면 "또 다른 클래스를 만들 필요 없이" 다양한 타입을 지원할 수 있다.

다음 컬렉션 예제를 보자.

List<int> intList = new List<int>();
List<string> strList = new List<string>();

intList.Add(10);
strList.Add("Hello");

제네릭 클래스를 사용하면, 저장되는 데이터의 타입에 관계없이 동일한 방식으로 추가/삭제 등의 작업을 수행할 수 있다.

ArrayList list = new ArrayList();
list.Add(10);   // int -> object (박싱)
list.Add("Hello");  // string -> object (박싱)

비제네릭 클래스의 경우 박싱/언박싱이 발생할 수 있어 성능에 영향을 줄 수 있다.

이처럼 제네릭은 특정 데이터 형식에 의존하지 않는 기능을 캡슐화하여, 코드의 재사용성과 확장성을 높이는 역할을 한다. 또한 컴파일 시점에 타입이 결정되므로 타입 안정성을 유지하면서도 유연한 설계를 할 수 있다.

System.Collections.Generic 네임스페이스에 있는 모든 자료구조 관련 클래스들은 제네릭 타입이다.
ex) List, Dictionary, LinkedList, Stack, Queue 등

public class MyClass<T>
{
    public T x;
    public T method(T p) { ... }
}

제네릭 클래스를 선언하는 방법은 클래스 이름 뒤에 <T>를 붙이면 된다. 이렇게 하면 클래스 내에서 사용되는 모든 데이터 타입을 T 하나로 처리할 수 있다. 클래스 이외에도 인터페이스나 메서드에도 적용될 수 있다.

C# 제네릭과 내부구조는 다르지만 비슷한 개념으로 C++의 템플릿이 있다.

제네릭 타입 제약 (Type Constraint)

제네릭 타입을 선언할 때, 타입 파라미터가 Value Type인지 Reference Type인지, 또는 어떤 특정 Base 클래스로부터 파생된 타입인지 제약을 걸 수 있다. 이는 where T : 제약조건 이런 식으로 where 뒤에 제약 조건을 붙이면 된다.

// Value 타입
class MyClass<T> where T : struct 

// Reference 타입
class MyClass<T> where T : class

// 디폴트 생성자 필요
class MyClass<T> where T : new() 

// MyBase의 파생클래스
class MyClass<T> where T : MyBase

// IComparable 인터페이스 필요
class MyClass<T> where T : IComparable

// 다중 제약
class EmployeeList<T> where T : Employee,
   IEmployee, IComparable<T>, new()

// 복수 타입 파라미터 제약
class MyClass<T, U> 
    where T : class 
    where U : struct

개방형? 폐쇄형?

제네릭 클래스가 다른 클래스를 상속 받을 때, 상속받는 클래스의 타입 매개변수가 확정되었는지 여부에 따라 개방형 또는 폐쇄형 제네릭 타입이라고 부른다.

개방형 제네릭 타입 (Open Constructed Type)

  • 하나 이상의 타입 매개변수가 확정되지 않은 경우
class NodeOpen<T> : BaseNodeGeneric<T> { } // BaseNodeGeneric<T>는 개방형

폐쇄형 제네릭 타입 (Closed Constructed Type)

  • 모든 타입 매개변수가 실제 타입으로 치환된 경우
class BaseNodeGeneric<T> { }
class NodeClosed<T> : BaseNodeGeneric<int> { }

// BaseNodeGeneric<int>는 폐쇄형.
// NodeClosed도 생성 과정에서 특정 타입으로 치환될 예정이기 때문에 완전 폐쇄형.

참고


제네릭 클래스(C# 프로그래밍 가이드)
C# 제네릭(C# Generics)
C# 실력다지기(2. 제네릭 클래스 이해하기)

profile
점진적 과부하

0개의 댓글