
C#에서 여러 개의 데이터를 한꺼번에 관리해야 할 때가 정말 많습니다.
이럴 때 사용하는 것이 바로 컬렉션(Collection)입니다.
이번 글에서는 C#의 역사를 함께한 ArrayList와
오늘날 표준으로 사용되는 List<T>에 대해 알아보겠습니다.
ArrayList는 제네릭(Generic) 개념이 없던 시절부터 사용되던 컬렉션입니다.
ArrayList의 가장 큰 특징은 어떤 타입의 데이터든 다 담을 수 있다는 점입니다.
[코드]
using System;
using System.Collections; // ArrayList를 사용하려면 필요합니다.
// ArrayList 사용법
ArrayList myArrayList = new ArrayList();
// 1. 데이터 추가 (Add) - 타입에 상관없이 다 들어갑니다.
myArrayList.Add(10); // 정수(int)
myArrayList.Add("Hello"); // 문자열(string)
myArrayList.Add(3.14); // 실수(double)
// 2. 데이터 사용 - 반드시 원래 타입으로 '형변환(Casting)' 해야 함!
int myInt = (int)myArrayList[0];
string myString = (string)myArrayList[1];
Console.WriteLine($"첫 번째 요소: {myInt}");
// 치명적인 문제점!
// string인 두 번째 요소를 int로 형변환하려고 시도하면?
// 컴파일 시점에는 오류가 없지만...
try
{
int wrongCast = (int)myArrayList[1]; // 런타임 오류 발생!
}
catch (InvalidCastException e)
{
Console.WriteLine($"오류: {e.Message}");
}
[실행 결과]
첫 번째 요소: 10
오류: Unable to cast object of type 'System.String' to type 'System.Int32'.
[문제점]
int나 double같은 값 형식(Value Type)을ArrayList에 넣으면, 내부적으로 object라는 참조 형식(Reference Type)으로<T> - 현대의 표준C# 2.0에서는 이러한 ArrayList의 단점을 해결하기 위해
제네릭(Generic) 기반의 컬렉션 List<T>가 등장했습니다.
이 리스트는 오직 한 가지 특정 타입의 데이터만 담겠다고 약속하는 것입니다.
[코드]
using System;
using System.Collections.Generic; // List<T>를 사용하려면 필요합니다.
// <int>를 지정하여 "이 리스트는 오직 정수(int)만 담을 수 있다"고 선언
List<int> myList = new List<int>();
// 1. 데이터 추가 (Add)
myList.Add(10);
myList.Add(20);
myList.Add(30);
// 2. 데이터 사용 - 형변환이 전혀 필요 없음!
int myInt = myList[0];
Console.WriteLine($"첫 번째 요소: {myInt}");
// 3. 다양한 유용한 메서드들
Console.WriteLine($"리스트의 개수: {myList.Count}");
myList.Remove(20); // 값이 20인 요소 제거
myList.Sort(); // 리스트 정렬
// myList.Add("Hello"); // 컴파일 오류 발생!
// 'string' 형식의 항목을 'int' 형식의 목록에 추가할 수 없습니다.
// -> 컴파일 시점에 실수를 바로잡아 줍니다! (타입 안정성)
[실행 결과]
첫 번째 요소: 10
리스트의 개수: 3
[문제점]
ArrayList보다 성능이 좋습니다.ArrayList와 List<T>는 비슷해 보이지만, 안정성과 성능 면에서 큰 차이가 있습니다.
레거시 코드 호환이라는 특별한 이유가 없다면, 항상 List<T>를 사용하세요!
| 구분 | ArrayList (권장되지 않음) | List<T> (권장) |
|---|---|---|
| 네임스페이스 | System.Collections | System.Collections.Generic |
| 타입 안정성 | (불안정), 런타임 오류 위험 | (안전), 컴파일 시점에서 체크 |
| 성능 | 상대적으로 느림 (박싱/언박싱 발생) | 빠름 (타입이 정해져 있음) |
| 핵심 | 모든 타입을 담을 수 있음 | 한 가지 특정 타입만 담을 수 있음 |