c# 제네릭(Generic) 클래스 및 정의

2024. 9. 29. 20:39c#

C# 제네릭 클래스 및 메서드 정의

C#에서 제네릭(Generics)은 다양한 타입을 하나의 클래스 또는 메서드에서 처리할 수 있게 해주는 강력한 기능입니다.
제네릭은 코드의 재사용성을 높이고, 타입 안정성을 보장하며, 더 적은 코드로 다양한 타입의 작업을 수행할 수 있게 해줍니다. 이번 포스팅에서는 제네릭 클래스제네릭 메서드의 개념과 사용법을 설명합니다.


1. 제네릭이란?

제네릭은 데이터 타입을 일반화하여 클래스, 메서드, 구조체, 인터페이스가 여러 데이터 타입에서 재사용될 수 있도록 해줍니다. 제네릭을 사용하면 타입에 대한 의존성을 줄이면서도 강력한 형식 검사를 통해 타입 안정성을 유지할 수 있습니다.

제네릭의 장점

  • 재사용성: 다양한 데이터 타입에 대해 동일한 코드를 작성할 수 있습니다.
  • 타입 안전성: 컴파일 타임에 타입 검사가 이루어져 런타임 오류를 줄일 수 있습니다.
  • 성능 향상: 박싱(Boxing)과 언박싱(Unboxing) 없이 성능을 최적화할 수 있습니다.

2. 제네릭 클래스 정의

제네릭 클래스는 하나의 클래스에서 여러 데이터 타입을 처리할 수 있도록 설계된 클래스입니다. 제네릭 클래스는 클래스 이름 뒤에 형식 매개변수를 지정하여 정의됩니다.

제네릭 클래스 예시

public class GenericClass<T>
{
    private T data;

    public GenericClass(T value)
    {
        data = value;
    }

    public T GetData()
    {
        return data;
    }

    public void SetData(T value)
    {
        data = value;
    }
}

위 예시에서는 T라는 형식 매개변수를 사용하여 제네릭 클래스를 정의하였습니다.
이 클래스는 T 타입의 데이터를 저장하고 반환하는 메서드를 제공합니다.

제네릭 클래스 사용 예시

GenericClass<int> intInstance = new GenericClass<int>(10);
Console.WriteLine(intInstance.GetData());  // 출력: 10

GenericClass<string> stringInstance = new GenericClass<string>("Hello");
Console.WriteLine(stringInstance.GetData());  // 출력: Hello

GenericClass<T>는 intstring 같은 다양한 타입에서 사용할 수 있으며, 각 인스턴스는 고유한 데이터 타입을 처리할 수 있습니다.


3. 제네릭 메서드 정의

제네릭 메서드는 특정 메서드가 다양한 데이터 타입에서 동작할 수 있도록 만들어진 메서드입니다.
제네릭 메서드는 메서드 이름 앞에 형식 매개변수를 사용하여 정의됩니다.

제네릭 메서드 예시

public class Utility
{
    public static void Print<T>(T item)
    {
        Console.WriteLine(item);
    }
}

Print<T> 메서드는 제네릭 메서드로, 매개변수로 전달된 데이터의 타입에 상관없이 그 값을 출력할 수 있습니다.

제네릭 메서드 사용 예시

Utility.Print<int>(100);      // 출력: 100
Utility.Print<string>("Hello");  // 출력: Hello
Utility.Print<double>(3.14);    // 출력: 3.14

각 호출에서 타입을 명시적으로 지정할 수 있지만, 컴파일러가 타입을 추론할 수 있는 경우 명시하지 않아도 됩니다.

Utility.Print(100);  // 타입 추론으로 인해 int로 처리
Utility.Print("Hello");  // 타입 추론으로 인해 string으로 처리

4. 제네릭의 제약조건 (Constraints)

때때로 제네릭 타입에 특정 제약을 걸어야 할 필요가 있습니다.
예를 들어, 제네릭 타입이 특정 인터페이스를 구현하거나 기본 생성자가 필요할 때 제약조건을 사용할 수 있습니다.

제약조건의 종류

  • where T : class – T는 참조형이어야 합니다.
  • where T : struct – T는 값 형식이어야 합니다.
  • where T : new() – T는 기본 생성자가 있어야 합니다.
  • where T : SomeBaseClass – T는 특정 클래스나 그 하위 클래스여야 합니다.
  • where T : ISomeInterface – T는 특정 인터페이스를 구현해야 합니다.

제네릭 제약조건 예시

public class Repository<T> where T : class, new()
{
    public T CreateInstance()
    {
        return new T();
    }
}

위 예시에서는 T가 클래스여야 하고, 기본 생성자가 있어야 한다는 제약을 걸었습니다.


5. 제네릭을 사용하는 실제 예

C#에서 제네릭은 컬렉션을 정의하는 데 자주 사용됩니다.
예를 들어, List<T>, Dictionary<TKey, TValue>, Queue<T>, Stack<T> 등 많은 컬렉션 클래스는 제네릭으로 정의되어 있어 다양한 데이터 타입을 처리할 수 있습니다.

List<T> 예시

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
numbers.Add(6);

foreach (int number in numbers)
{
    Console.WriteLine(number);
}

이러한 제네릭 컬렉션은 타입 안전성을 보장하며, 박싱/언박싱 없이 성능을 최적화할 수 있습니다.


 

제네릭 클래스제네릭 메서드는 C#에서 코드의 재사용성을 극대화하는 중요한 도구입니다.
제네릭을 사용하면 다양한 타입에 대해 동일한 코드를 작성할 수 있으며, 타입 안정성을 유지하면서 더 간결하고 유연한 코드를 구현할 수 있습니다. 또한, 제네릭 제약조건을 사용하여 더 강력한 타입 검사를 구현할 수 있습니다.

제네릭을 통해 코드의 가독성을 높이고 유지보수성을 향상시키는 것은 물론, 프로그램의 성능을 최적화할 수 있습니다.