C# Generics


제네릭 소개 (Introduction to Generics)

제네릭(Generics)은 C#에서 타입의 재사용성을 높이고, 타입 안정성을 확보하며, 코드의 중복을 줄이는 강력한 기능입니다. 제네릭을 사용하면 클래스, 메서드, 인터페이스 등을 정의할 때 특정 데이터 타입에 구애받지 않고, 여러 타입을 사용할 수 있습니다. 이는 코드의 유연성을 높이고, 타입 안전성을 보장하여 런타임 오류를 줄이는 데 도움이 됩니다.

제네릭의 기본 개념 (Basic Concepts of Generics)

제네릭은 일반적인 데이터 타입을 사용하여 클래스, 메서드 또는 인터페이스를 정의할 수 있는 기능을 제공합니다. 제네릭을 사용하면 다음과 같은 이점을 얻을 수 있습니다.

  • 타입 안정성: 컴파일 타임에 타입 검사가 이루어져 타입 오류를 줄일 수 있습니다.
  • 코드 재사용성: 하나의 제네릭 클래스를 정의하고 여러 타입으로 인스턴스를 생성하여 재사용할 수 있습니다.
  • 성능 향상: 제네릭을 사용하면 타입 변환 및 캐스팅이 필요 없어 성능을 향상시킬 수 있습니다.

제네릭 클래스 (Generic Classes)

제네릭 클래스를 사용하면 다양한 데이터 타입에 대해 유연하게 작동하는 클래스를 정의할 수 있습니다.

예제: 제네릭 클래스 정의 (Defining a Generic Class)

public class Box<T>
{
    private T _content;

    public void SetContent(T content)
    {
        _content = content;
    }

    public T GetContent()
    {
        return _content;
    }
}

이 예제는 Box<T>라는 제네릭 클래스를 정의합니다. T는 타입 매개변수로, 인스턴스를 생성할 때 구체적인 타입을 지정합니다.

예제: 제네릭 클래스 사용 (Using a Generic Class)

public class Program
{
    public static void Main(string[] args)
    {
        Box<int> intBox = new Box<int>();
        intBox.SetContent(123);
        Console.WriteLine($"Integer value: {intBox.GetContent()}");

        Box<string> strBox = new Box<string>();
        strBox.SetContent("Hello, Generics!");
        Console.WriteLine($"String value: {strBox.GetContent()}");
    }
}

이 예제는 Box<int>Box<string> 타입의 인스턴스를 생성하고, 각각의 SetContentGetContent 메서드를 호출하여 제네릭 클래스를 사용하는 방법을 보여줍니다.

제네릭 메서드 (Generic Methods)

제네릭 메서드는 메서드의 매개변수 또는 반환 타입에 대해 제네릭을 사용하는 방법입니다. 제네릭 메서드는 호출 시점에 타입을 지정할 수 있습니다.

예제: 제네릭 메서드 정의 (Defining a Generic Method)

public class Utility
{
    public static T FindMax<T>(T a, T b) where T : IComparable<T>
    {
        return a.CompareTo(b) > 0 ? a : b;
    }
}

이 예제는 제네릭 메서드 FindMax<T>를 정의합니다. 이 메서드는 두 값을 비교하여 더 큰 값을 반환합니다. TIComparable<T>를 구현해야 합니다.

예제: 제네릭 메서드 사용 (Using a Generic Method)

public class Program
{
    public static void Main(string[] args)
    {
        int maxInt = Utility.FindMax(10, 20);
        Console.WriteLine($"Maximum integer: {maxInt}");

        string maxStr = Utility.FindMax("apple", "banana");
        Console.WriteLine($"Maximum string: {maxStr}");
    }
}

이 예제는 FindMax 메서드를 호출하여 정수와 문자열의 최대 값을 찾는 방법을 보여줍니다.

제네릭 인터페이스 (Generic Interfaces)

제네릭 인터페이스는 타입 매개변수를 사용하는 인터페이스입니다. 제네릭 인터페이스를 사용하면 타입에 대한 제약을 두고 인터페이스를 정의할 수 있습니다.

예제: 제네릭 인터페이스 정의 (Defining a Generic Interface)

public interface IRepository<T>
{
    void Add(T item);
    T Get(int id);
    IEnumerable<T> GetAll();
}

이 예제는 제네릭 인터페이스 IRepository<T>를 정의합니다. 이 인터페이스는 데이터 항목을 추가하고, 조회하며, 모든 항목을 반환하는 메서드를 포함합니다.

예제: 제네릭 인터페이스 구현 (Implementing a Generic Interface)

public class InMemoryRepository<T> : IRepository<T>
{
    private readonly Dictionary<int, T> _storage = new Dictionary<int, T>();
    private int _nextId = 1;

    public void Add(T item)
    {
        _storage[_nextId++] = item;
    }

    public T Get(int id)
    {
        _storage.TryGetValue(id, out T item);
        return item;
    }

    public IEnumerable<T> GetAll()
    {
        return _storage.Values;
    }
}

이 예제는 IRepository<T> 인터페이스를 구현한 InMemoryRepository<T> 클래스를 정의합니다. 이 클래스는 메모리에 데이터를 저장하고, 항목을 추가하고 조회하는 방법을 제공합니다.

제네릭 타입 제약 (Generic Type Constraints)

제네릭 타입 제약을 사용하면 제네릭 타입 매개변수에 대해 제약 조건을 설정할 수 있습니다. 이를 통해 제네릭 클래스나 메서드가 특정 조건을 만족하는 타입만을 사용할 수 있도록 제한할 수 있습니다.

예제: 제네릭 타입 제약 (Using Generic Type Constraints)

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

이 예제는 T가 클래스이며 기본 생성자를 가져야 한다는 제약 조건을 설정합니다. new() 제약 조건을 사용하여 타입 T의 인스턴스를 생성할 수 있습니다.

결론 (Conclusion)

제네릭(Generics)은 C#에서 타입 안정성과 코드 재사용성을 높이는 강력한 기능입니다. 제네릭 클래스를 사용하면 여러 타입에 대해 유연한 코드를 작성할 수 있으며, 제네릭 메서드는 메서드의 매개변수나 반환 타입에 제네릭을 사용하여 재사용성을 높입니다. 제네릭 인터페이스와 제약 조건을 사용하면 타입의 제약을 설정하고 더 안전하고 유연한 코드를 작성할 수 있습니다. 제네릭을 통해 코드의 중복을 줄이고, 컴파일 타임에 타입 검사를 수행함으로써 더 안전하고 유지보수 가능한 애플리케이션을 개발할 수 있습니다.


Posted in C#

Leave a Reply

Your email address will not be published. Required fields are marked *