학습 일자 : 2023.04.10
클래스 또는 함수가 코드에 의해 선언되고 인스턴스화 될 때까지 형식의 사양을 연기하는 디자인 (특정 타입에 국한되지 않고, 모든 타입을 멤버 변수의 타입으로 설정이 가능하다)
거의 모든 부분이 동일하지만 일부 자료형만이 다른 경우 사용
→ 일반화를 사용하지 않는 경우, 필요한 자료형 마다 함수를 작성해 줘야 함
일반화를 이용하면 위 함수들과 다른 자료형의 함수 또한 호환할 수 있음
박싱, 언박싱 과정에서 소모되는 불필ㄹ요한 연산을 하지 않아도 됨.
<T> 키워드를 사용해서 일반화 선언함. (T = Type의 약자)
<aside> 💡 제네릭 기본 형태
class (클래스명)<T> //제네릭 클래스 { ...클래스 내용 ...
//제네릭 변수
public T objMember { get; set; }
//제네릭 함수
public T (메소드명)<T> (T 변수명)
{
…함수내용…
}
}
</aside>
→ 제네릭 함수는 일반 함수에서도 사용이 가능 함.
[일반함수에서 사용한 제네릭 예제]
public void ArrayCopy<T>(T[] src, T[] dst)
{
dst = new T[src.Length];
for (int i = 0; i < src.Length; i++) { dst[i] = src[i]; }
}
public void Test2()
{
int[] iSrc = { 1, 2, 3, 4, 5 }, iDst = null;
float[] fSrc = { 1f, 2f, 3f, 4f, 5f }, fDst = null;
double[] dSrc = { 1d, 2d, 3d, 4d, 5d }, dDst = null;
// 일반화된 함수로 자료형과 무관한 함수 구현
ArrayCopy<int>(iSrc, iDst); // 자료형을 함수 호출당시 결정
ArrayCopy<float>(fSrc, fDst);
ArrayCopy<double>(dSrc, dDst);
char[] cSrc = { 'a', 'b', 'c' }, cDst = null;
ArrayCopy(cSrc, cDst);
/*자료형을 함수 호출 당시 결정 함
-> 매개 변수를 넘겨줄 때 T가 어떤 자료형인지 알 수 있음
-> <(자료형)>생략 가능 */
}
일반화 자료형을 선언할 때 제약 조건을 선언하여, 일반화가 가능한 자료형을 제한함.
일반화 자료형에 제약 조건이 있다면 포함 가능한 자료형의 기능을 사용할 수 있음.
“where”키워드를 활용 함
<aside> 💡 제약 사항 기본 형태
클래스명<T> where T : (자료형1), (자료형2), …. 메소드명<T> where T : (자료형1), (자료형2), ….
</aside>
⇒ :(클론) 뒤에 쓴 자료형만 T에 들어올 수 있음을 뜻함
⇒ 클래스의 상속과 동일함 → 제약 조건을 class는 하나만 가능, 인터페이스는 여러 개 가능함
[제네릭 제약사항 예제]
// <일반화 자료형 제약>
// 일반화 자료형을 선언할 때 제약조건을 선언하여, 일반화가 가능한 자료형을 제한
class StructClass<T> where T : struct { } // T는 Value 타입
class ClassClass<T> where T : class { } // T는 Reference 타입
class InterfaceClass<T> where T : IComparable { }
// T는 IComparable 인터페이스를 가져야 함 (상속 받아야 함)
class ParentClass { }
class ChildClass<T> where T : ParentClass { } // T는 파생클래스이어야 함
public class MyBase
{
public void Start() { Console.WriteLine("시작"); }
}
class Generic
{
//MyBase 또는 MyBase 상속 받은 클래스만 사용 가능 -> MyBase의 함수도 이용 가능함
public void Test3<T>(T param) where T : MyBase { param.Start(); }
public void Test4()
{
StructClass<int> structClass = new StructClass<int>();
// int는 구조체이므로 struct 제약조건이 있는 일반화 가능
// ClassClass<int> classClass = new ClassClass<int>();
// error : int는 구조체이므로 class 제약조건이 있는 일반화 불가
}
}