본문 바로가기
Program Language/C#

Part3. C# 실력 다지기(2. 제네릭 클래스 이해하기)

by 토담이아빠 2023. 3. 27.

제네릭 클래스

 

지난 포스팅의 제네릭 메서드에 이어 이번 포스팅에서는 제네릭 클래스에 대해서 다루어 보겠습니다.

 

제네릭 클래스란?

 

제네릭 클래스는 멤버의 형을 일반화된 타입인 <T>로 표시한 클래스입니다. 이렇게 하면 클래스 내에서 사용되는 모든 데이터 타입을 T 하나로 처리할 수 있습니다.

 

제네릭 클래스 선언

 

 

제네릭 클래스를 선언하는 방법은 클래스 이름 뒤에 <T>을 붙이면 됩니다. 이렇게 하면 객체가 생성될 때 <> 안에 쓰는 형이 T를 대체하게 됩니다. 


public class MyGenericClass<T>
{
    public T x;
    public T method(T p) { ... }
}

여기서  T는 일반화된 타입 매개변수입니다. float, int, double, string 등 어떤 타입이라도 될 수 있습니다. 클래스를 위와 같이 선언하면 다음과 같이 사용될 수 있습니다.


MyGenericClass<int> x = new MyGenericClass<int>();
MyGenericClass<string> str = new MyGenericClass<string>();

 

제네릭 클래스의 사용 예제

 

좀 더 자세한 사용 예제를 보겠습니다. 다음은 리스트 클래스를 제네릭으로 선언하여 사용하는 예제입니다.


using System;

class Program
{
    class List<T>
    {
        private T[] elements;
        private int count;

        public List()
        {
            elements = new T[10];
            count = 0;
        }

        public void Add(T element)
        {
            elements[count] = element;
            count++;
        }

        public T Get(int index)
        {
            return elements[index];
        }
    }

    static void Main(string[] args)
    {
        List<int> intList = new List<int>();
        intList.Add(1);
        intList.Add(2);
        Console.WriteLine(intList.Get(0)); // 출력: 1

        List<string> stringList = new List<string>();
        stringList.Add("Hello");
        stringList.Add("World");
        Console.WriteLine(stringList.Get(1)); // 출력: World
    }

}
[결과]

1
World

위 코드는 제네릭으로 선언된 List 클래스를 이용하여 List<int> 타입의 intList를 생성합니다. List<int>는 T를 int로 지정하여 정수 리스트를 다루고, stringList는 List<string> 타입의 인스턴스를 생성하여, T를 string으로 지정하여 문자열 리스트를 다룹니다.

 

제한된 제네릭 클래스

 

제한된 제네릭 클래스는 제네릭 클래스의 타입 매개변수에 대한 제한을 둘 수 있는 기능입니다. 제한된 제네릭 클래스를 사용하면, 제네릭 클래스가 특정 타입에 대해서만 동작하도록 제한할 수 있습니다.

 

제한된 제네릭 클래스를 사용하는 방법은 where 키워드를 사용하여 타입 매개변수에 대한 제약 조건을 설정하는 것입니다. where 키워드를 사용하면, 타입 매개변수가 특정 조건을 만족하는 경우에만 클래스를 사용할 수 있도록 제한할 수 있습니다. 

 

예를 들어, 숫자 타입에 대해서만 덧셈 연산을 수행하는 제네릭 클래스의 경우, 숫자 타입에 대해서만 덧셈을 지원하도록 제한할 필요가 있습니다.


using System;

class Program
{
    class NumericAdder<T> where T : struct
    {
        public T Add(T a, T b)
        {
            if (typeof(T) == typeof(int))
            {
                return (T)(object)((int)(object)a + (int)(object)b);
            }
            else if (typeof(T) == typeof(double))
            {
                return (T)(object)((double)(object)a + (double)(object)b);
            }
            else if (typeof(T) == typeof(float))
            {
                return (T)(object)((float)(object)a + (float)(object)b);
            }
            else
            {
                throw new ArgumentException("Unsupported type");
            }
        }
    }

    static void Main(string[] args)
    {
        NumericAdder<int> intAdder = new NumericAdder<int>();
        int result1 = intAdder.Add(1, 2); // 결과: 3

        NumericAdder<double> doubleAdder = new NumericAdder<double>();
        double result2 = doubleAdder.Add(1.5, 2.5); // 결과: 4.0

        NumericAdder<string> stringAdder = new NumericAdder<string>(); // 컴파일 에러 발생!
    }

}

위 코드에서 NumericAdder<T> 클래스는 T 타입 매개변수를 가지며, Add 메서드를 제공합니다. 그러나 where T : struct 제약 조건으로 인해 값 타입에 대해서만 동작하도록 제한됩니다. 

 

intAdder은 NumericAdder<int> 타입의 인스턴스를 생성하고, doubleAdder은 NumericAdder<double> 타입의 인스턴스를 생성하여 int와 double 타입에 대한 덧셈을 수행할 수 있습니다. 

 

그러나, stringAdder의 경우, NumericAdder<string> 타입의 인스턴스를 생성하려고 하므로 컴파일 에러가 발생합니다.(string은 참조타입)


댓글