컬렉션으로 저장하고 조작할 때 유사한 데이터를 보다 효율적으로 처리할 수 있는 경우가 많습니다. 클래스 또는 System.Array 클래스와 System.Collections, System.Collections.Generic, System.Collections.Concurrent, System.Collections.Immutable 네임스페이스의 클래스를 사용하여 컬렉션에서 개별 요소 또는 요소 범위를 추가, 제거 및 수정할 수 있습니다.
컬렉션에는 두 가지 주요 형식이 있습니다. 제네릭 컬렉션 및 제네릭이 아닌 컬렉션입니다. 제네릭 컬렉션은 컴파일 시 형식이 안전합니다. 따라서 제네릭 컬렉션은 일반적으로 더 나은 성능을 제공합니다. 제네릭 컬렉션은 생성될 때 형식 매개 변수를 허용합니다. 컬렉션에서 항목을 추가하거나 제거할 때 형식에서 Object 캐스팅할 필요가 없습니다. 또한 대부분의 일반 컬렉션은 Windows 스토어 앱에서 지원됩니다. 제네릭이 아닌 컬렉션은 항목을 저장할 때 Object 캐스팅이 필요하며, 이로 인해 대부분이 Windows 스토어 앱 개발에 지원되지 않습니다. 그러나 이전 코드에는 제네릭이 아닌 컬렉션이 표시될 수 있습니다.
.NET Framework 4 이상 버전에서 네임스페이스의 System.Collections.Concurrent 컬렉션은 여러 스레드에서 컬렉션 항목에 액세스하기 위한 효율적인 스레드로부터 안전한 작업을 제공합니다. 네임스페이스(System.Collections.Immutable)의 변경할 수 없는 컬렉션 클래스는 원래 컬렉션의 복사본에서 작업을 수행하고 원래 컬렉션을 수정할 수 없으므로 기본적으로 스레드로부터 안전합니다.
일반적인 컬렉션 기능
모든 컬렉션은 컬렉션에서 항목을 추가, 제거 또는 찾기 위한 메서드를 제공합니다. 또한 ICollection 인터페이스 또는 ICollection<T> 인터페이스를 직접 또는 간접적으로 구현하는 모든 컬렉션은 이러한 기능을 공유합니다.
컬렉션을 열거하는 기능
.NET 컬렉션은 컬렉션을 반복할 수 있도록 System.Collections.IEnumerable 또는 System.Collections.Generic.IEnumerable<T>을 구현합니다. 열거자는 컬렉션의 모든 요소에 대한 이동 가능한 포인터로 생각할 수 있습니다. foreach, in statement 및 For Each… Next 문은 GetEnumerator 메서드에 의해 노출되는 열거자를 사용하고, 열거자를 조작하는 복잡성을 숨깁니다. 또한 구현 System.Collections.Generic.IEnumerable<T> 하는 모든 컬렉션은 쿼리 가능한 형식 으로 간주되며 LINQ를 사용하여 쿼리할 수 있습니다. LINQ 쿼리는 데이터에 액세스하기 위한 일반적인 패턴을 제공합니다. 일반적으로 표준
foreach
루프보다 간결하고 읽기 가능하며 필터링, 순서 지정 및 그룹화 기능을 제공합니다. LINQ 쿼리는 성능을 향상시킬 수도 있습니다. 자세한 내용은 LINQ to Objects(C#), LINQ to Objects(Visual Basic), PLINQ(병렬 LINQ),LINQ 쿼리 소개(C#) 및 기본 쿼리 작업(Visual Basic)을 참조하세요.컬렉션 콘텐츠를 배열에 복사하는 기능
모든 컬렉션은 메서드를 사용하여
CopyTo
배열에 복사할 수 있습니다. 그러나 새 배열의 요소 순서는 열거자가 반환하는 시퀀스를 기반으로 합니다. 결과 배열은 항상 하한이 0인 1차원입니다.
또한 많은 컬렉션 클래스에는 다음과 같은 기능이 포함되어 있습니다.
용량 및 개수 속성
컬렉션의 용량은 포함할 수 있는 요소의 수입니다. 컬렉션의 수는 실제로 포함된 요소의 수입니다. 일부 컬렉션은 용량 또는 개수 또는 둘 다를 숨깁니다.
현재 용량에 도달하면 대부분의 컬렉션이 자동으로 용량으로 확장됩니다. 메모리가 다시 할당되고 요소가 이전 컬렉션에서 새 컬렉션으로 복사됩니다. 이 디자인은 컬렉션을 사용하는 데 필요한 코드를 줄입니다. 그러나 컬렉션의 성능에 부정적인 영향을 미칠 수 있습니다. 예를 들어 List<T>에서, Count이 Capacity보다 작으면 항목을 추가하는 것은 O(1) 작업입니다. 새 요소를 수용하기 위해 용량을 늘려야 하는 경우 항목을 추가하면 O(
n
) 작업이n
Count됩니다. 여러 재할당으로 인한 성능 저하를 방지하는 가장 좋은 방법은 초기 용량을 컬렉션의 예상 크기로 설정하는 것입니다.A BitArray 는 특별한 경우입니다. 용량은 길이와 같으며 개수와 동일합니다.
일관된 하한
컬렉션의 하한은 첫 번째 요소의 인덱스입니다. 네임스페이스의 System.Collections 모든 인덱싱된 컬렉션은 하한이 0이므로 0으로 인덱싱됩니다. Array에는 기본적으로 하한이 0이지만 , 을 사용하여 Array.CreateInstance 클래스의 인스턴스를 만들 때 다른 하한을 정의할 수 있습니다.
여러 스레드에서 액세스하기 위한 동기화 (System.Collections 클래스에만 해당).
네임스페이스 System.Collections의 제네릭이 아닌 컬렉션 형식은 동기화를 통해 일부 스레드 보안을 제공하며, 일반적으로 SyncRoot 및 IsSynchronized 멤버를 통해 노출됩니다. 이러한 컬렉션은 기본적으로 스레드로부터 안전하지 않습니다. 컬렉션에 확장 가능하고 효율적인 다중 스레드 액세스가 필요한 경우 네임스페이스의 System.Collections.Concurrent 클래스 중 하나를 사용하거나 변경할 수 없는 컬렉션을 사용하는 것이 좋습니다. 자세한 내용은 Thread-Safe 컬렉션을 참조하세요.
컬렉션 선택
일반적으로 제네릭 컬렉션을 사용해야 합니다. 다음 표에서는 이러한 시나리오에 사용할 수 있는 몇 가지 일반적인 컬렉션 시나리오 및 컬렉션 클래스에 대해 설명합니다. 제네릭 컬렉션을 처음으로 사용하는 경우 다음 표는 작업에 가장 적합한 제네릭 컬렉션을 선택하는 데 도움이 됩니다.
하고 싶어요... | 제네릭 컬렉션 옵션 | 제네릭이 아닌 컬렉션 옵션 | 스레드에 안전하거나 불변하는 컬렉션 옵션 |
---|---|---|---|
키별 빠른 조회를 위해 항목을 키/값 쌍으로 저장 | Dictionary<TKey,TValue> | Hashtable (키의 해시 코드를 기반으로 구성된 키/값 쌍의 컬렉션입니다.) |
ConcurrentDictionary<TKey,TValue> ReadOnlyDictionary<TKey,TValue> ImmutableDictionary<TKey,TValue> |
인덱스별 항목 액세스 | List<T> | Array ArrayList |
ImmutableList<T> ImmutableArray |
아이템을 선입선출 방식으로 사용하세요 | Queue<T> | Queue | ConcurrentQueue<T> ImmutableQueue<T> |
후입선출(LIFO) 방식으로First-Out 데이터를 사용하기 | Stack<T> | Stack | ConcurrentStack<T> ImmutableStack<T> |
순차적으로 항목 액세스 | LinkedList<T> | 권장 사항 없음 | 권장 사항 없음 |
항목이 제거되거나 컬렉션에 추가될 때 알림을 받습니다. (구현 INotifyPropertyChanged 그리고 INotifyCollectionChanged) | ObservableCollection<T> | 권장 사항 없음 | 권장 사항 없음 |
정렬된 컬렉션 | SortedList<TKey,TValue> | SortedList | ImmutableSortedDictionary<TKey,TValue> ImmutableSortedSet<T> |
수학 함수 집합 | HashSet<T> SortedSet<T> |
권장 사항 없음 | ImmutableHashSet<T> ImmutableSortedSet<T> |
컬렉션의 알고리즘 복잡성
컬렉션 클래스를 선택할 때 성능의 잠재적인 절충을 고려할 가치가 있습니다. 다음 표를 사용하여 알고리즘 복잡성에서 다양한 변경 가능한 컬렉션 형식이 해당 변경할 수 없는 컬렉션 형식과 비교하는 방법을 참조합니다. 변경할 수 없는 컬렉션 형식은 성능이 떨어지지만 불변성을 제공하는 경우가 많으며 이는 종종 유효한 비교 이점입니다.
변경 가능 | 상환 | 최악의 경우 | 변경 불가능 | 복잡성 |
---|---|---|---|---|
Stack<T>.Push |
O(1) | O(n ) |
ImmutableStack<T>.Push |
O(1) |
Queue<T>.Enqueue |
O(1) | O(n ) |
ImmutableQueue<T>.Enqueue |
O(1) |
List<T>.Add |
O(1) | O(n ) |
ImmutableList<T>.Add |
O(log n ) |
List<T>.Item[Int32] |
O(1) | O(1) | ImmutableList<T>.Item[Int32] |
O(log n ) |
List<T>.Enumerator |
O(n ) |
O(n ) |
ImmutableList<T>.Enumerator |
O(n ) |
HashSet<T>.Add 조회 |
O(1) | O(n ) |
ImmutableHashSet<T>.Add |
O(log n ) |
SortedSet<T>.Add |
O(log n ) |
O(n ) |
ImmutableSortedSet<T>.Add |
O(log n ) |
Dictionary<T>.Add |
O(1) | O(n ) |
ImmutableDictionary<T>.Add |
O(log n ) |
Dictionary<T> 조회 |
O(1) | O(1) – 또는 엄밀하게 O(n ) |
ImmutableDictionary<T> 조회 |
O(log n ) |
SortedDictionary<T>.Add |
O(log n ) |
O(n log n ) |
ImmutableSortedDictionary<T>.Add |
O(log n ) |
List<T>
는 for
루프 또는 foreach
루프를 사용하여 효율적으로 열거할 수 있습니다. 그러나 인덱서의 O(로그 ImmutableList<T>
) 시간으로 인해 for
루프 안에서는 효율적이지 않습니다.
ImmutableList<T>
를 foreach
루프를 사용하여 열거하는 것은 ImmutableList<T>
가 데이터를 저장할 때 List<T>
배열 대신 이진 트리를 사용하기 때문에 효율적입니다. 배열을 빠르게 인덱싱할 수 있는 반면, 원하는 인덱스가 있는 노드가 발견될 때까지 이진 트리를 아래로 이동해야 합니다.
SortedSet<T>
또한 둘 다 이진 트리를 사용하기 때문에 복잡성이 ImmutableSortedSet<T>
동일합니다. 중요한 차이점은 변경할 수 없는 이진 트리를 사용한다는 ImmutableSortedSet<T>
것입니다.
ImmutableSortedSet<T>
또한 변형을 허용하는 클래스를 System.Collections.Immutable.ImmutableSortedSet<T>.Builder 제공하므로 불변성과 성능을 모두 가질 수 있습니다.
관련 문서
제목 | 설명 |
---|---|
컬렉션 클래스 선택 | 다양한 컬렉션을 설명하고 시나리오에 맞게 컬렉션을 선택하는 데 도움이 됩니다. |
일반적으로 사용되는 컬렉션 형식 | 일반적으로 사용되는 제네릭 및 제네릭이 아닌 컬렉션 형식(예: System.Array, System.Collections.Generic.List<T>및 System.Collections.Generic.Dictionary<TKey,TValue>)에 대해 설명합니다. |
제네릭 컬렉션을 사용하는 경우 | 제네릭 컬렉션 형식의 사용에 대해 설명합니다. |
컬렉션 내의 비교 및 정렬 | 컬렉션에서 같음 비교 및 정렬 비교의 사용에 대해 설명합니다. |
정렬된 컬렉션 형식 | 정렬된 컬렉션 성능 및 특성을 설명합니다. |
해시 테이블 및 사전 컬렉션 형식 | 제네릭 및 제네릭이 아닌 해시 기반 사전 형식의 기능을 설명합니다. |
Thread-Safe 모음집 | 여러 스레드에서 안전하고 효율적인 동시 액세스를 지원하는 컬렉션 System.Collections.Concurrent.BlockingCollection<T>System.Collections.Concurrent.ConcurrentBag<T> 형식에 대해 설명합니다. |
System.Collections.Immutable | 변경할 수 없는 컬렉션을 소개하고 컬렉션 형식에 대한 링크를 제공합니다. |
참고 문헌
.NET