📕제네릭(Generics)이란?
📖제네릭이란?
제네릭이란 구체적인 데이터 형식이 정해지지 않은 형식으로, 클래스와 인터페이스, 추상 클래스, 필드, 메서드, 정적 메서드, 프로퍼티, 이벤트, 델리게이트에서 사용될 수 있다.
데이터 형식이 정해지지 않았기 때문에 제네릭 형식을 사용할 땐 데이터 형식이 들어갈 자리를 표시해 줘야 하는데, 이를 형식 매개 변수라고 한다. 형식 매개 변수의 이름은 정해진 바가 없으나 일반적으로 타입의 첫 글자인 T를 사용한다.
제네릭 형식을 선언하는 방법은 다음과 같다.
class DataStore<T>
{
public T Data { get; set; }
}
위 코드에서 DataSotre는 제네릭 클래스이며 T는 형식 매개 변수다. Data는 구체적인 데이터 형식 대신 T를 사용해 선언되었으므로 제네릭 프로퍼티다.
class KeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
}
형식 매개 변수가 여러 개일 때는 위처럼 콤마를 사용해 나타낼 수 있다.
💡형식 매개 변수가 하나뿐일 때는 T만 써도 충분하지만 매개 변수가 여러 개라면 가독성을 고려해 이름을 지어야 한다.
📌형식 매개 변수 제약
제네릭 형식에서 형식 매개 변수의 범주를 제한하고 싶다면 where 키워드를 사용하면 된다. 구체적인 형식은 다음과 같다.
GenericTypeName<T> where T : constraint1, constraint2
where T : constraint1, constraint2의 의미는 constraint1, constraint2 형식만 T가 될 수 있도록 제한한다는 의미이다.
class DataStore<T> where T : class
{
public T Data { get; set; }
}
마찬가지로 위 코드에서 where T : class는 class 형식만 T가 될 수 있도록 제한한다는 의미이다. 이때 제약 조건 class는 멤버로 구성된 데이터 구조가 아니라 참조 형식 전체이다. 즉, 참조 형식인 string과 delegate 등도 포함된다.
📖제네릭의 사용
📌제네릭의 장점
제네릭을 사용했을 때의 장점은 크게 세 가지이다.
- 코드의 재사용성을 높인다. 같은 동작을 수행하는데 데이터 형식만 다르다면 제네릭을 사용해 서로 다른 데이터 형식을 처리할 수 있다.
- 제약 조건에 맞지 않는 매개 변수를 사용할 경우 컴파일 오류가 발생하므로 안전하다.
- 형변환이 발생하지 않으므로 성능 낭비를 줄일 수 있다.
📌제네릭 클래스
제네릭 클래스를 사용하려면 new 키워드로 객체를 생성해야 한다.
DataStore<string> store = new DataStore<string>();
store라는 이름으로 위에서 정의한 DataStore 클래스의 객체를 생성했다. 형식 매개 변수는 string으로 지정했다. 따라서 DataStore 클래스의 모든 T는 string 형식이 된다.
다음으로는 Data 프로퍼티에 값을 할당해 주었다.
DataStore<string> store = new DataStore<string>();
store.Data = "Hello World!";
//store.Data = 123; //compile-time error
stroe.Data = "Hello World!";의 경우 Data의 형식과 "Hello World!"의 형식이 일치하므로 정상적으로 작동한다. 반면 주석 처리 된 store.Data = 123;를 실행하면 컴파일 오류가 발생한다.
📌제네릭 필드
제네릭으로 선언한 필드는 초기화할 수 없다.
class DataStore<T>
{
public T data;
}
배열은 다음과 같이 사용한다.
class DataStore<T>
{
public T[] data = new T[10];
}
📌제네릭 메서드 in generic Class
class DataStore<T>
{
private T[] _data = new T[10];
public void AddOrUpdate(int index, T item)
{
if(index >= 0 && index < 10)
_data[index] = item;
}
public T GetData(int index)
{
if(index >= 0 && index < 10)
return _data[index];
else
return default(T);
}
}
위 코드에는 제네릭 메서드 AddOrUpdate와 GetData가 정의되어 있다. AddOrUpdate는 반환 형식은 없고 매개 변수 형식은 int와 T이다. GetData는 반환 형식이 T이고 매개 변수 형식은 int이다. 두 메서드의 T는 DataStore<T> 클래스가 생성될 때 정해진다.
DataStore<string> cities = new DataStore<string>();
cities.AddOrUpdate(0, "Mumbai");
cities.AddOrUpdate(1, "Chicago");
cities.AddOrUpdate(2, "London");
DataStore<int> empIds = new DataStore<int>();
empIds.AddOrUpdate(0, 50);
empIds.AddOrUpdate(1, 65);
empIds.AddOrUpdate(2, 89);
📌제네릭 메서드 in Non-generic Class
class Printer
{
public void Print<T>(T data)
{
Console.WriteLine(data);
}
}
Printer printer = new Printer();
printer.Print<int>(100);
printer.Print(200); // type infer from the specified value
printer.Print<string>("Hello");
printer.Print("World!"); // type infer from the specified value
제네릭 클래스가 아닌 클래스에서 제네릭 메서드를 정의할 땐 메서드 이름 옆에 <T>를 추가한다.
🔖인용 및 참고
Generic Type Parameters - C# Programming Guide
Learn about generic type definition in C#, where a type parameter is a placeholder for a type that a client specifies for an instance of the generic type.
docs.microsoft.com
https://www.tutorialsteacher.com/csharp/constraints-in-generic-csharp
C# Generic Constraints
C# Generic Constraints C# allows you to use constraints to restrict client code to specify certain types while instantiating generic types. It will give a compile-time error if you try to instantiate a generic type using a type that is not allowed by the s
www.tutorialsteacher.com
https://www.tutorialsteacher.com/csharp/csharp-generics
C# Generics
C# Generics Generic means the general form, not specific. In C#, generic means not specific to a particular data type. C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, an
www.tutorialsteacher.com
'C#' 카테고리의 다른 글
[C#] 딕셔너리(Dictionary) (0) | 2022.07.08 |
---|---|
[C#]리플렉션(Reflection)과 어트리뷰트(Attribute) (0) | 2022.07.06 |
구조체(Struct)와 클래스(Class) (0) | 2022.06.17 |
생성자 (0) | 2022.06.17 |
프로퍼티(Property, 속성) (0) | 2022.06.14 |