비제네릭 컬렉션
비제네릭 컬렉션은 .NET Framework 1.0에서 도입된 자료 구조로, 다양한 타입의 데이터를 유연하게 저장할 수 있는 컬렉션 클래스들을 의미합니다. System.Collections
네임스페이스에 포함되어 있으며, 당시에는 데이터 관리의 핵심 도구로 사용되었습니다. 그러나 제네릭 컬렉션Generic Collections 도입된 이후 타입 안전성과 성능 면에서 한계를 보이기 시작했으며, 현대적인 개발에서는 사용이 권장되지 않습니다.
비제네릭 컬렉션의 종류
ArrayList
ArrayList
는 다양한 타입의 객체를 저장할 수 있는 동적 배열입니다. 배열의 크기를 유연하게 변경할 수 있다는 장점이 있지만, 모든 요소가 object
타입으로 저장되기 때문에 타입 안전성이 부족하고, 값 타입을 저장할 때 박싱Boxing과 언박싱Unboxing이 발생하여 성능 저하가 있을 수 있습니다.
ArrayList arrayList = new ArrayList();
arrayList.Add(1);
arrayList.Add("Hello");
arrayList.Add(3.14);
// 요소 출력
foreach (var item in arrayList)
{
Console.WriteLine(item);
}
- 타입 캐스팅 오류 예제
ArrayList arrayList = new ArrayList();
arrayList.Add(1);
arrayList.Add("Hello");
foreach (var item in arrayList)
{
try
{
int number = (int)item; // InvalidCastException 발생 가능
Console.WriteLine(number);
}
catch (InvalidCastException)
{
Console.WriteLine("타입 캐스팅 오류 발생!");
}
}
Hashtable
Hashtable
은 키-값 쌍으로 데이터를 저장하는 해시 테이블입니다. 해시 기반으로 데이터를 저장하므로, 키를 이용한 빠른 검색이 가능하지만 키와 값 모두 object
타입으로 저장되기 때문에 타입 캐스팅이 필요합니다.
Hashtable hashtable = new Hashtable();
hashtable.Add("key1", 100);
hashtable.Add("key2", "Hello World");
hashtable.Add("key3", 3.14);
foreach (DictionaryEntry entry in hashtable)
{
Console.WriteLine($"{entry.Key}: {entry.Value}");
}
- 타입 캐스팅 오류 예제
Hashtable hashtable = new Hashtable();
hashtable.Add("key1", 100);
hashtable.Add("key2", "Hello World");
try
{
int value = (int)hashtable["key2"]; // InvalidCastException 발생
}
catch (InvalidCastException)
{
Console.WriteLine("타입 캐스팅 오류 발생!");
}
Queue
Queue
는 FIFOFirst In First Out 방식으로 데이터를 관리하는 컬렉션으로, 데이터를 순서대로 처리해야 할 때 주로 사용됩니다.
Queue queue = new Queue();
queue.Enqueue(1);
queue.Enqueue("Hello");
queue.Enqueue(3.14);
while (queue.Count > 0)
{
var item = queue.Dequeue();
Console.WriteLine(item);
}
Stack
Stack
은 LIFOLast In First Out 방식으로 데이터를 관리하는 컬렉션입니다. 후입선출 구조로, 호출 스택이나 역순 처리, 재귀적인 데이터 관리와 같은 기능을 구현할 때 유용합니다.
Stack stack = new Stack();
stack.Push(1);
stack.Push("Hello");
stack.Push(3.14);
while (stack.Count > 0)
{
var item = stack.Pop();
Console.WriteLine(item);
}
비제네릭 컬렉션의 특징과 한계
타입 안전성 부족
비제네릭 컬렉션은 모든 요소를 object
타입으로 저장하기 때문에, 데이터를 사용할 때마다 명시적인 타입 캐스팅이 필요합니다. 이는 다음과 같은 문제를 야기합니다:
- 런타임 오류 발생 가능성 증가: 잘못된 타입으로 캐스팅할 경우
InvalidCastException
이 발생합니다. - 코드 가독성 저하: 반복적인 타입 캐스팅으로 코드가 복잡해집니다.
- 유지보수성 감소: 타입 관련 버그가 발생할 확률이 높아집니다.
박싱과 언박싱
값 타입(예: int
, double
)을 비제네릭 컬렉션에 저장할 때 박싱이 발생하여 힙 메모리에 할당됩니다. 이후 값을 가져올 때 언박싱이 필요하며, 이는 성능 저하의 원인이 됩니다.
- 박싱Boxing: 값 타입을 참조 타입으로 변환하여 힙에 할당.
- 언박싱Unboxing: 힙에 있는 객체를 다시 값 타입으로 변환.
유연성의 양면성
다양한 타입의 데이터를 하나의 컬렉션에 저장할 수 있다는 유연성은 장점이지만, 타입 안정성을 해치고 코드의 안전성을 떨어뜨립니다.
제네릭 컬렉션으로의 전환
비제네릭 컬렉션의 단점들을 해결하기 위해 .NET Framework 2.0
부터 제네릭 컬렉션이 도입되었습니다. 제네릭 컬렉션은 타입을 명시적으로 지정할 수 있어 타입 안전성을 보장하며, 박싱/언박싱으로 인한 성능 저하를 피할 수 있습니다. 따라서, 새로운 개발에서는 List, Dictionary 등의 제네릭 컬렉션을 사용하는 것이 권장됩니다.
제네릭 컬렉션으로의 전환은 코드의 안정성과 성능을 모두 개선할 수 있는 중요한 변화입니다. 기존의 비제네릭 컬렉션을 제네릭으로 전환함으로써 코드의 가독성과 유지보수성을 높일 수 있습니다.