제네릭(Generic) 타입

Shy·2025년 3월 17일

C#

목록 보기
26/27

Generic

제네릭(Generic)은 자료형(타입)을 일반화하여 코드의 재사용성과 유연성을 높이는 기능이다.

제네릭을 사용하면 특정 타입에 종속되지 않고, 다양한 타입에서 동작하는 클래스를 만들 수 있다.

제네릭이 필요한 이유는 다음과 같다.

  1. 코드의 중복을 줄일 수 있다.
  2. 타입 안정성(type safety)를 제공한다.
  3. 성능 최적화 (박싱/언박싱을 피할 수 있다.)

1. 제네릭 클래스

제네릭 클래스를 사용하면 다양한 타입을 수용할 수 있는 클래스를 만들 수 있다.

예제: 일반적인 컬렉션 클래스

public class MyList<T>
{
    private T[] items;
    private int count = 0;

    public MyList(int size)
    {
        items = new T[size];
    }

    public void Add(T item)
    {
        if (count < items.Length)
        {
            items[count] = item;
            count++;
        }
    }

    public T GetItem(int index)
    {
        return items[index];
    }
}

사용 예시

MyList<int> intList = new MyList<int>(5);
intList.Add(10);
intList.Add(20);
Console.WriteLine(intList.GetItem(1)); // 20

MyList<string> stringList = new MyList<string>(3);
stringList.Add("Hello");
Console.WriteLine(stringList.GetItem(0)); // Hello
  • T는 사용자가 지정하는 타입이며, intstring 등 어떤 타입도 가능하다.

2. 제네릭 메서드

클래스 전체가 아니라 특정 메서드만 제네릭으로 만들 수도 있다.

예제: 두 값을 교환하는 제네릭 메서드

public class Utils
{
    public static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }
}

사용 예시

int x = 5, y = 10;
Utils.Swap(ref x, ref y);
Console.WriteLine($"x: {x}, y: {y}"); // x: 10, y: 5

string s1 = "Hello", s2 = "World";
Utils.Swap(ref s1, ref s2);
Console.WriteLine($"s1: {s1}, s2: {s2}"); // s1: World, s2: Hello

3. 제네릭 인터페이스

제네릭 인터페이스를 사용하면 다양한 타입을 지원하는 인터페이스를 만들 수 있다.

예제: 제네릭 인터페이스

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

사용 예시

public class UserRepository : IRepository<string>
{
    private Dictionary<int, string> users = new Dictionary<int, string>();

    public void Add(string item)
    {
        int id = users.Count + 1;
        users[id] = item;
    }

    public string Get(int id)
    {
        return users.ContainsKey(id) ? users[id] : null;
    }
}

IRepository<string> repo = new UserRepository();
repo.Add("Alice");
repo.Add("Bob");
Console.WriteLine(repo.Get(1)); // Alice
Console.WriteLine(repo.Get(2)); // Bob

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

제네릭을 사용할 때 특정 조건을 강제하고 싶다면 제약 조건(Constraints)을 사용할 수 있다.

예제: 특정 클래스 상속 제한

public class BaseEntity
{
    public int Id { get; set; }
}

public class Repository<T> where T : BaseEntity
{
    private List<T> items = new List<T>();

    public void Add(T item)
    {
        items.Add(item);
    }

    public T FindById(int id)
    {
        return items.FirstOrDefault(x => x.Id == id);
    }
}

public class User : BaseEntity
{
    public string Name { get; set; }
}

public class Product : BaseEntity
{
    public string ProductName { get; set; }
}

사용 예시

Repository<User> userRepo = new Repository<User>();
userRepo.Add(new User { Id = 1, Name = "Alice" });
Console.WriteLine(userRepo.FindById(1)?.Name); // Alice

Repository<Product> productRepo = new Repository<Product>();
productRepo.Add(new Product { Id = 1, ProductName = "Laptop" });
Console.WriteLine(productRepo.FindById(1)?.ProductName); // Laptop
  • where T : BaseEntity를 사용하여 BaseEntity를 상속받은 클래스만 사용할 수 있도록 제한했다.

정리

개념설명
제네릭 클래스여러 타입을 지원하는 클래스 (class MyList<T> {})
제네릭 메서드특정 메서드만 제네릭으로 사용 (public static void Swap<T>(ref T a, ref T b))
제네릭 인터페이스다양한 타입을 지원하는 인터페이스 (interface IRepository<T> {})
제네릭 제약 조건특정 타입만 허용 (where T : BaseEntity)
profile
신입사원...

0개의 댓글