c# 제네릭(Generic)과 컬렉션(Collection)의 관계의 유연성 확보

2024. 9. 29. 21:06c#

제네릭과 컬렉션의 관계: 유연성 확보

C#에서 제네릭(Generics)컬렉션(Collections)은 밀접하게 연관되어 있습니다.
제네릭을 활용한 컬렉션은 코드의 유연성, 재사용성, 타입 안정성을 동시에 확보할 수 있게 해줍니다.
이번 포스팅에서는 제네릭과 컬렉션의 관계를 살펴보고, 이 둘이 어떻게 유연성을 높이는 데 기여하는지에 대해 설명합니다.


1. 제네릭과 컬렉션이란?

제네릭(Generics)

제네릭은 다양한 데이터 타입에 대해 유연하게 동작할 수 있도록 설계된 C#의 기능입니다.
제네릭을 사용하면 데이터 타입에 상관없이 코드가 재사용될 수 있으며, 타입 안정성을 보장하여 컴파일 시 오류를 사전에 방지할 수 있습니다.

컬렉션(Collections)

컬렉션은 데이터를 집합적으로 저장하고 관리하는 구조입니다.
배열과 달리 동적으로 크기를 변경할 수 있으며, 여러 자료구조(리스트, 딕셔너리, 스택 등)로 데이터를 효율적으로 관리할 수 있습니다.


2. 제네릭을 활용한 컬렉션의 유연성

제네릭을 사용한 컬렉션은 특정 자료형에 구애받지 않고 여러 데이터 타입을 처리할 수 있는 장점이 있습니다. C#에서 대표적으로 사용되는 제네릭 컬렉션은 다음과 같습니다:

  • List<T>: 동적으로 크기가 변경되는 배열.
  • Dictionary<TKey, TValue>: 키-값 쌍으로 데이터를 저장하는 해시 테이블.
  • Stack<T>: LIFO(Last In, First Out) 방식으로 데이터를 저장하는 스택.
  • Queue<T>: FIFO(First In, First Out) 방식으로 데이터를 저장하는 큐.

제네릭 컬렉션의 예

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
Dictionary<string, int> wordCounts = new Dictionary<string, int>
{
    { "apple", 1 },
    { "banana", 2 },
    { "cherry", 3 }
};

위 예제에서는 List<T>와 Dictionary<TKey, TValue>와 같은 제네릭 컬렉션이 사용되었습니다.
이러한 컬렉션은 특정 타입에 의존하지 않으며, 다양한 데이터 타입에 대해 동일한 방식으로 유연하게 사용할 수 있습니다.


3. 제네릭 컬렉션의 장점

1) 타입 안정성

제네릭 컬렉션은 타입 안정성을 제공합니다.
즉, 컬렉션에 저장할 수 있는 데이터 타입이 컴파일 시 결정되므로, 잘못된 데이터 타입을 삽입하는 것을 방지할 수 있습니다.

List<string> names = new List<string> { "John", "Jane" };
// names.Add(123); // 컴파일 오류 발생 (타입 안정성 제공)

제네릭을 사용하지 않는 컬렉션에서는 데이터를 추가할 때 타입 캐스팅이 필요하며, 잘못된 캐스팅으로 인한 런타임 오류가 발생할 가능성이 있습니다. 하지만 제네릭을 사용하면 이러한 오류를 사전에 방지할 수 있습니다.

2) 코드 재사용성

제네릭 컬렉션을 사용하면 다양한 타입의 데이터를 처리하는 동일한 코드를 작성할 수 있어, 코드 재사용성이 높아집니다. 동일한 컬렉션 구조를 여러 타입에 대해 사용할 수 있으므로, 불필요한 코드 중복을 줄일 수 있습니다.

3) 성능 최적화

제네릭은 박싱(Boxing)언박싱(Unboxing)을 방지하여 성능을 최적화할 수 있습니다. 박싱은 값 타입을 참조 타입으로 변환하는 작업인데, 이는 성능에 영향을 미칩니다. 제네릭을 사용하면 이러한 변환 과정을 없애기 때문에 성능 향상을 기대할 수 있습니다.


4. 제네릭 컬렉션의 유연성 예시

List<T>와 ArrayList 비교

제네릭이 도입되기 전, C#에서는 ArrayList와 같은 비제네릭 컬렉션을 사용하였습니다. ArrayList는 다양한 타입의 데이터를 담을 수 있었지만, 모든 데이터가 object 타입으로 저장되기 때문에 성능 저하와 타입 오류 가능성이 있었습니다.

ArrayList arrayList = new ArrayList();
arrayList.Add(1);
arrayList.Add("Hello");
arrayList.Add(true);

int firstElement = (int)arrayList[0]; // 타입 캐스팅 필요

List<T>는 제네릭을 사용하여 동일한 기능을 제공하면서도 타입 안전성과 성능을 보장합니다.

List<int> numberList = new List<int> { 1, 2, 3 };
numberList.Add(4); // 타입 안정성 보장, 캐스팅 불필요

Dictionary<TKey, TValue>의 유연성

Dictionary<TKey, TValue>는 제네릭을 사용하여 키와 값을 다양한 타입으로 저장할 수 있습니다.
이로 인해 하나의 사전에서 다양한 데이터를 유연하게 처리할 수 있습니다.

Dictionary<string, int> ageDictionary = new Dictionary<string, int>
{
    { "John", 30 },
    { "Jane", 25 },
    { "Bob", 22 }
};

Console.WriteLine(ageDictionary["John"]); // 출력: 30

키와 값의 타입을 제네릭으로 정의하여 다양한 자료형에 대해 유연하게 사용할 수 있습니다.


5. 제네릭을 통한 컬렉션의 유연성 확보

제네릭 컬렉션은 강력한 타입 안정성을 제공하면서도, 다양한 자료형에 대해 유연하게 동작할 수 있습니다.
이로 인해 컬렉션에서 데이터를 추가, 삭제, 검색하는 작업이 매우 간편해지며, 다양한 상황에서 컬렉션을 재사용할 수 있습니다.

예시 - 제네릭 컬렉션과 메서드

public void AddToCollection<T>(List<T> collection, T item)
{
    collection.Add(item);
}

List<string> stringList = new List<string>();
AddToCollection(stringList, "Hello");

List<int> intList = new List<int>();
AddToCollection(intList, 100);

위의 예시에서 제네릭 메서드는 List<T> 타입을 인자로 받으며, 어떤 타입의 리스트이든 유연하게 동작합니다. 이는 제네릭과 컬렉션의 결합을 통해 유연성을 확보하는 좋은 예입니다.


 

제네릭과 컬렉션의 결합은 C#에서 코드의 유연성, 재사용성, 타입 안전성, 성능 최적화를 가능하게 해줍니다.
제네릭 컬렉션을 사용하면 다양한 자료형에 대해 동일한 코드로 처리할 수 있으며, 이로 인해 코드가 간결해지고 유지보수성이 향상됩니다.

제네릭 컬렉션은 실무에서 매우 많이 사용되며, 이를 적극 활용하면 더욱 효율적이고 확장성 있는 프로그램을 작성할 수 있습니다. C#에서 제네릭과 컬렉션의 관계를 깊이 이해하고 이를 적절히 활용하는 것이 중요합니다.