List<T>는 인덱스로 접근할 수 있고, 정렬·검색·수정을 위한 다양한 메서드를 제공하는 강력한 형식(Strongly Typed)의 개체 컬렉션입니다. System.Collections.Generic 네임스페이스에 속하며, 사실상 ArrayList의 제네릭 버전이라고 할 수 있습니다.
List<T>는 IList<T> 인터페이스를 구현하며, ArrayList와 동일한 역할을 수행하지만 다음과 같은 장점이 있습니다.
- 지정된 형식의 요소만 저장할 수 있습니다.
- 제네릭이므로 컴파일 타임에 형식 검사가 이루어지고, 박싱(Boxing)·언박싱(Unboxing)이 발생하지 않습니다.
- Add(), AddRange() 메서드 또는 컬렉션 이니셜라이저 구문으로 요소를 추가할 수 있습니다.
- myList[0]처럼 배열과 동일하게 인덱스로 요소에 접근할 수 있으며, 인덱스는 0부터 시작합니다.
- ArrayList보다 실행 속도가 빠르고 오류 발생 가능성도 낮습니다.
일반적으로 리스트는 인덱스, for/foreach 루프, LINQ 쿼리를 통해 접근하지만, 경우에 따라서는 반복문 없이 한 줄의 코드로 리스트 전체 또는 일부를 새 리스트에 복사하고 싶을 때가 있습니다. 아래에서 foreach 없이 리스트를 복사하는 세 가지 방법을 소개합니다.
방법 1: 생성자를 사용한 복사
List<T> 생성자에 기존 리스트를 인수로 전달하면, 원본 리스트의 모든 요소를 포함하는 새 리스트가 생성됩니다. 가장 간단하고 직관적인 방법입니다.
class Program{
public static void Main(){
List<int> originalList = new List<int>(){1,2,3,4,5,7,8,9};
List<Int32> copy = new List<Int32>(originalList);
foreach (var item in copy){
System.Console.WriteLine(item);
}
Console.ReadLine();
}
}출력 결과
1
2
3
4
5
7
8
9
방법 2: ToList() 메서드 사용
LINQ에서 제공하는 ToList() 확장 메서드를 사용하면 IEnumerable 시퀀스를 새 List로 변환할 수 있습니다. 원본 리스트의 모든 요소가 복사된 새 리스트를 반환하므로, 간결한 문법으로 전체 복사가 가능합니다.
class Program{
public static void Main(){
List<int> originalList = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9 };
List<Int32> copy = originalList.ToList();
foreach (var item in copy){
System.Console.WriteLine(item);
}
Console.ReadLine();
}
}출력 결과
1
2
3
4
5
7
8
9
방법 3: GetRange() 메서드 사용
GetRange(index, count) 메서드는 지정한 시작 인덱스부터 지정한 개수만큼의 요소로 구성된 새 리스트를 반환합니다. 리스트의 일부분만 복사하고 싶을 때 특히 유용합니다. 아래 예제에서는 인덱스 0부터 3개의 요소를 복사합니다.
class Program{
public static void Main(){
List<int> originalList = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9 };
List<Int32> copy = originalList.GetRange(0, 3);
foreach (var item in copy){
System.Console.WriteLine(item);
}
Console.ReadLine();
}
}출력 결과
1
2
3
세 가지 방법 비교 및 주의 사항
- 생성자 복사(new List<T>(original)): 전체 복사에 가장 널리 쓰이는 표준적인 방법입니다.
- ToList(): LINQ 스타일의 간결한 문법으로, 배열이나 IEnumerable 컬렉션에도 동일하게 적용할 수 있습니다.
- GetRange(): 시작 인덱스와 개수를 지정해 리스트의 특정 구간만 복사할 수 있다는 점이 차별화됩니다.
다만 이 방법들은 모두 얕은 복사(Shallow Copy)라는 점에 유의해야 합니다. 값 형식(int, double 등)에는 완벽하게 동작하지만, 참조 형식(클래스 개체)을 담은 리스트의 경우 개체 자체가 아니라 참조만 복사되므로, 두 리스트가 같은 개체를 공유하게 됩니다. 깊은 복사가 필요하다면 직접 복제 로직을 구현하거나 직렬화 기법을 활용해야 합니다.