Unity 개발일지

[C#] Generic 본문

C#

[C#] Generic

아머르 2024. 6. 28. 18:43

[Generic 이란?]

타입 매개변수를 사용하여 클래스, 구조체, 인터페이스, 메서드 등을 정의할 수 있게 하는 기능으로, Generic을 사용하면 데이터 타입에 의존하지 않는 재사용가능한 코드를 작성할 수 있다. 이는 코드의 타입 안전성을 높이고, 성능을 향상시키며, 코드 중복을 줄이는 데 도움을 준다.

쉽게 말하면, 제네릭은 다양한 데이터 타입에 하나의 함수나 클래스를 정의할 수 있도록 하는 프로그래밍의 기법이다.

 

< 제네릭 클래스 예시>

'T'라는 타입 매개변수를 받아들이며, 이 타입은 클래스가 인스턴스화될 때 구체적으로 결정된다.

new 키워드로 int와 string 타입의 제네릭 클래스를 인스턴스화 하였다.

 

<제네릭 메서드 예시>

매개변수로 받은 타입 'T'를 이용하여 데이터를 출력한다.

더보기

<여러 개의 타입이 들어간 제네릭>

[Generic을 어떻게 활용해야하나?]

1. 여러 데이터 형식에 의해 동일한 로직을 적용해야할 때

2. 제네릭 컬랙션을 활용할 때

 

게임 컨텐츠 로직보다는 게임 뒤에서 리소스 관리같은 시스템 로직에 더 많이 활용된다.

참고: 제네릭은 코드의 유연성과 재사용성을 높이지만, 남용하면 코드의 가독성이 떨어질 수 있다.

 

[Generic의 제약(Constraints)]

제약은 특정한 조건을 만족하는 클래스나 구조체만 활용할 수 있게 하는 문법으로,

적절한 제약은 타입을 검사하거나 타입을 활용하여 처리하는 로직을 우회할 수 있어 런타임 성능을 매우 높일 수 있다.

 

1. where T : U

 형식 인수가 U 클래스를 상속받아야 한다.

더보기

형식 매개변수 'T'가 특정 클래스 'U'를 상속받아야 함을 의미한다.

즉, 'T' 는 'U' 또는 'U'의 파생 클래스여야 한다.

 

2. where T : new()

 형식 인수에 매개 변수가 없는 public 생성자가 있어야 한다. 다른 제약조건과 함께 사용할 경우 new() 제약 조건을 마지막에 지정해야 한다. new() 제약조건은 struct 또는 unmanaged제약 조건과 결합할 수 없다.

더보기

형식 매개변수 'T'에 매개변수가 없는  public 생성자가 있어야 한다.  다른 제약 조건과 함께 사용할 경우 new() 제약 조건을 마지막에 지정해야한다.

 

3. where T : struce

 형식 인수는 null을 허용하지 않는 값 형식이어야 한다. 모든 값 형식에 액세스 할 수 있는 매개 변수가 없는 생성자가 있으므로, struct 제약조건은 new() 제약조건을 나타내고, new() 제약 조건과 결합할 수 없다. struct 제약조건을 unmanaged

제약 조건과 결합할 수 없다.

더보기

형식 매개변수 'T'가 값 형식이어야 한다. 'struct' 제약 조건은 기본적으로 new() 제약 조건을 포함하므로 별도로 결합할 필요가 없다.

 

4. where T : class

 형식 인수는 참조형식이어야 한다. 이 제약 조건은 모든 클래스, 인터페이스, 대리자 또는 배열 형식에도 적용된다.

더보기

형식 매개변수 'T'가 참조 형식이어야 함을 의미한다. 모든 클래스, 인터페이스, 대리자 또는 배열 형식에도 적용된다.

 

5. where T : class?

형식 인수는 null을 허용하거나 null을 허용하지 않는 참조 형식이어야 한다. 이 제약 조건은 모든 클래스, 인터페이스, 대리자 또는 배열 형식에도 적용된다.

더보기

형식 매개변수 'T'가 null을 허용하거나 null을 허용하지 않는 참조 형식이어야 함을 의미한다. 이 제약 조건은 nullable 참조형식에 적용할 수 있다.

 

[제네릭 제약조건의 활용 예시]

제네릭 제약조건을 사용하면 특정 타입만 허용하므로 더 안전하고 효율적인 코드를 작성할 수 있다.

예를들어, 제네릭 메서드를 작성할 때 매개변수 타입이 특정 인터페이스를 구현해야 하는 경우, 해당 인터페이스를 제약조건으로 지정할 수 있다.

해당 코드는 <where T : class> 제약조건으로,

MyGenericClass<T> 클래스는 제약조건이 IMyInterface이므로 해당 Interface를 구현해야한다.

MyClass는 IMyInterface를 상속하므로 MyMethod 메서드를 구현해야한다.

 

MyGenericClass<MyClass> 타입의 obj는 MyClass가 IMyInterface를 구현하므로 유효한 제네릭 타입 매개변수이고,

Execute 메서드는 'T' 타입의 매게변수를 받아 MyMethod를 호출할 수 있다.

 

이는 제네릭 제약조건을 사용하여 'T'가 특정 인터페이스를 구현해야한다는 것을 강제함으로써 타입 안전성을 보장한다.

 

 

나중에 써먹으려고 Archiveing 해놓은 GenericSingleton

 

유니티에서 많이들 사용하는 GenericSingleton은 <where T : U> 제약 조건에 해당하며 여기서 U는 MonoBehaviour.

이 제약조건은 'T'가 반드시 MonoBehaviour를 상속받아야 한다. 이 제약 조건을 사용하면 GenericSingleton<T> 클래스는 MonoBehaviour를 상속받는 타입만을 제네릭 타입 매개 변수로 허용하게 되며, 이는 Unity의 컴포넌트 시스템과 호환되는 타입들만 사용하도록 보장한다.

 

 

반응형