비고
이 콘텐츠는 프레임워크 디자인 지침: 재사용 가능한 .NET 라이브러리에 대한 규칙, 관용구 및 패턴, 2판에서 Pearson Education, Inc.의 권한으로 다시 인쇄됩니다. 이 버전은 2008년에 출판되었으며, 이후 세 번째 에디션에서 완전히 수정되었습니다. 이 페이지의 일부 정보는 오래된 것일 수 있습니다.
공통된 특성을 가진 개체 그룹을 조작하도록 특별히 설계된 모든 형식은 컬렉션으로 간주될 수 있습니다. 이러한 타입이 IEnumerable 또는 IEnumerable<T>를 구현하는 것은 거의 항상 적절하므로 이 섹션에서는 이러한 인터페이스 중 하나 또는 둘 다를 구현하는 타입만 컬렉션으로 간주합니다.
❌ 공용 API에서 약한 형식의 컬렉션을 사용하지 마세요.
컬렉션 항목을 나타내는 모든 반환 값 및 매개 변수의 형식은 해당 기본 형식이 아닌 정확한 항목 형식이어야 합니다(컬렉션의 공용 멤버에만 적용됨).
❌ 공용 API에서는 ArrayList 또는 List<T>를 사용하지 마세요.
이러한 형식은 공용 API가 아닌 내부 구현에서 사용하도록 설계된 데이터 구조입니다.
List<T>
는 API의 정리와 유연성을 희생하여 성능과 전력에 최적화되어 있습니다. 예를 들어 반환 List<T>
하는 경우 클라이언트 코드에서 컬렉션을 수정할 때 알림을 받을 수 없습니다.
List<T>
또한 많은 시나리오에서 유용하거나 적용할 수 없는 많은 멤버(예: BinarySearch)를 노출합니다. 다음 두 섹션에서는 공용 API에서 사용하도록 특별히 설계된 형식(추상화)에 대해 설명합니다.
❌ 공용 API에서는 Hashtable
또는 Dictionary<TKey,TValue>
를 사용하지 마세요.
이러한 형식은 내부 구현에 사용하도록 설계된 데이터 구조입니다. 공용 API는 IDictionary나 IDictionary <TKey, TValue>
또는 하나나 둘 다의 인터페이스를 구현하는 사용자 지정 형식을 사용해야 합니다.
❌ 메서드의 반환 형식으로 사용되는 경우를 제외하고 IEnumerator<T>, IEnumerator, 또는 이러한 인터페이스 중 하나를 구현하는 다른 형식을 사용하지 마세요.
GetEnumerator
메서드 이외의 메서드에서 열거자를 반환하는 형식은 foreach
구문과 함께 사용할 수 없습니다.
❌ 동일한 형식에서 둘 다 IEnumerator<T>
IEnumerable<T>
구현하지 마세요. 동일한 사항이 비제네릭 인터페이스 IEnumerator
및 IEnumerable
에 적용됩니다.
컬렉션 매개 변수
✔️ DO 매개 변수 형식으로 가능한 최소 특수 형식을 사용합니다. 컬렉션을 매개 변수로 사용하는 대부분의 멤버는 인터페이스를 IEnumerable<T>
사용합니다.
❌속성에 액세스하기 위해 ICollection<T> 또는 ICollection를 매개 변수로 사용하지 마십시오Count
.
대신 IEnumerable<T>
또는 IEnumerable
을(를) 사용하고 개체가 ICollection<T>
나 ICollection
를 구현하는지 동적으로 확인하는 것이 좋습니다.
컬렉션 속성 및 반환 값
❌ 설정 가능한 컬렉션 속성을 제공하지 마세요.
사용자는 먼저 컬렉션을 지우고 새 콘텐츠를 추가하여 컬렉션의 콘텐츠를 바꿀 수 있습니다. 전체 컬렉션을 바꾸는 것이 일반적인 시나리오인 경우 컬렉션에 메서드를 AddRange
제공하는 것이 좋습니다.
✔️ 읽기/쓰기 컬렉션을 나타내는 속성 또는 반환 값에 대해 Collection<T>
또는 Collection<T>
의 하위 클래스를 사용합니다.
일부 요구 사항을 충족하지 못할 경우 Collection<T>
가 필요한 경우(예를 들어, 컬렉션이 IList를 구현해서는 안 되는 경우), IEnumerable<T>
, ICollection<T>
, 또는 IList<T>를 구현하여 사용자 지정 컬렉션을 사용하세요.
✔️ DO는 읽기 전용 컬렉션을 나타내는 속성 또는 반환 값의 하위 클래스 ReadOnlyCollection<T>또는 드문 경우 ReadOnlyCollection<T>
를 사용합니다IEnumerable<T>
.
일반적으로 ReadOnlyCollection<T>
을(를) 선호합니다. 일부 요구 사항을 충족하지 않는 경우(예: 컬렉션이 IList
를 구현해서는 안 되는 경우), IEnumerable<T>
, ICollection<T>
, 또는 IList<T>
을(를) 구현하여 사용자 지정 컬렉션을 사용하세요. 사용자 지정 읽기 전용 컬렉션을 구현하는 경우 ICollection<T>.IsReadOnly
를 구현하고 true
을 반환하도록 합니다.
지원하려는 유일한 시나리오가 전방 전용 반복이라고 확신하는 경우 간단히 사용할 IEnumerable<T>
수 있습니다.
✔️ 컬렉션을 직접 사용하는 대신 제네릭 기본 컬렉션의 하위 클래스를 사용하는 것이 좋습니다.
이렇게 하면 더 나은 이름을 사용할 수 있으며 기본 컬렉션 형식에 없는 도우미 멤버를 추가할 수 있습니다. 이는 특히 상위 수준 API에 적용할 수 있습니다.
일반적으로 사용되는 메서드 및 속성에서 Collection<T>
또는 ReadOnlyCollection<T>
의 하위 클래스를 반환하는 것을 고려하십시오.
이렇게 하면 나중에 도우미 메서드를 추가하거나 컬렉션 구현을 변경할 수 있습니다.
✔️ 컬렉션에 저장된 항목에 고유 키(이름, ID 등)가 있는 경우 키 지정된 컬렉션을 사용하는 것이 좋습니다. 키드 컬렉션은 정수와 키로 인덱싱할 수 있는 컬렉션으로, 일반적으로 KeyedCollection<TKey,TItem>
에서 상속하여 구현됩니다.
키 컬렉션은 일반적으로 메모리 공간이 더 크며 메모리 오버헤드가 키를 갖는 이점보다 크면 사용하지 않아야 합니다.
❌ 컬렉션 속성 또는 컬렉션을 반환하는 메서드에서 null 값을 반환하지 마세요. 대신 빈 컬렉션 또는 빈 배열을 반환합니다.
일반적인 규칙은 null 및 비어 있는(0개 항목) 컬렉션 또는 배열을 동일하게 처리해야 한다는 것입니다.
스냅샷 및 라이브 컬렉션
특정 시점의 상태를 나타내는 컬렉션을 스냅샷 컬렉션이라고 합니다. 예를 들어 데이터베이스 쿼리에서 반환된 행이 포함된 컬렉션은 스냅샷입니다. 항상 현재 상태를 나타내는 컬렉션을 라이브 컬렉션이라고 합니다. 예를 들어 항목 컬렉션 ComboBox
은 라이브 컬렉션입니다.
❌ 속성에서 스냅샷 컬렉션을 반환하지 마세요. 속성은 라이브 컬렉션을 반환해야 합니다.
속성 getter는 매우 간단한 작업이어야 합니다. 스냅샷을 반환하려면 O(n) 작업에서 내부 컬렉션의 복사본을 만들어야 합니다.
✔️ 스냅샷 컬렉션 또는 라이브 IEnumerable<T>
(또는 해당 하위 형식)를 사용하여 일시적(즉, 컬렉션을 명시적으로 수정하지 않고 변경할 수 있는) 컬렉션을 나타냅니다.
일반적으로 공유 리소스를 나타내는 모든 컬렉션(예: 디렉터리의 파일)은 일시적입니다. 구현이 단순히 정방향 전용 열거자가 아닌 한 이러한 컬렉션은 라이브 컬렉션으로 구현하기가 매우 어렵거나 불가능합니다.
배열과 컬렉션 중에서 선택
✔️ 배열보다 컬렉션을 선호합니다.
컬렉션은 콘텐츠에 대한 더 많은 제어를 제공하고, 시간이 지남에 따라 진화할 수 있으며, 더 많이 사용할 수 있습니다. 또한 배열 복제 비용이 엄청나기 때문에 읽기 전용 시나리오에 배열을 사용하는 것은 권장되지 않습니다. 유용성 연구에 따르면 일부 개발자는 컬렉션 기반 API를 사용하는 것이 더 편한 것으로 나타났습니다.
그러나 하위 수준 API를 개발하는 경우 읽기/쓰기 시나리오에 배열을 사용하는 것이 더 좋을 수 있습니다. 배열의 메모리 공간이 작아 작업 집합을 줄이는 데 도움이 되며, 런타임에 의해 최적화되므로 배열의 요소에 대한 액세스 속도가 더 빠릅니다.
✔️ 낮은 수준의 API에서 배열을 사용하여 메모리 소비를 최소화하고 성능을 최대화하는 것이 좋습니다.
✔️ 바이트 컬렉션 대신 바이트 배열을 사용합니다.
❌ 속성 getter가 호출될 때마다 속성이 새 배열(예: 내부 배열의 복사본)을 반환해야 하는 경우 속성에 배열을 사용하지 마세요.
사용자 지정 컬렉션 구현
✔️ 새 컬렉션을 디자인할 때 Collection<T>
, ReadOnlyCollection<T>
, KeyedCollection<TKey,TItem>
에서 상속을 고려하세요.
✔️ 새 컬렉션을 디자인할 때 IEnumerable<T>
을 구현하십시오. 구현 ICollection<T>
또는 IList<T>
타의 추이를 고려합니다.
이러한 사용자 지정 컬렉션을 구현하는 경우 가능한 한 밀접하게 설정된 Collection<T>
ReadOnlyCollection<T>
API 패턴을 따릅니다. 즉, 동일한 멤버를 명시적으로 구현하고, 이러한 두 컬렉션과 같은 매개 변수 이름을 지정하는 등의 작업을 합니다.
✔️ 컬렉션이 종종 이러한 인터페이스를 입력으로 사용하는 API에 전달되는 경우 비제네릭 컬렉션 인터페이스(IList
및 ICollection
)를 구현하는 것이 좋습니다.
❌ 컬렉션 개념과 관련이 없는 복잡한 API가 있는 형식에서 컬렉션 인터페이스를 구현하지 마세요.
❌ 와 같은 CollectionBase
비제네릭 기본 컬렉션에서 상속하지 마세요. 대신 Collection<T>
, ReadOnlyCollection<T>
및 KeyedCollection<TKey,TItem>
(을)를 사용하세요.
사용자 지정 컬렉션 이름 지정
컬렉션(IEnumerable
을 구현하는 형식)은 주로 두 가지 이유로 생성됩니다. (1) 구조에 특화된 작업을 수행하며 기존 데이터 구조(예: List<T>, LinkedList<T>, Stack<T>)와는 다른 성능 특성을 가진 새 데이터 구조를 만들기 위해서, (2) 특정 항목 집합(예: StringCollection)을 보유하기 위한 특수 컬렉션을 만들기 위해서입니다. 데이터 구조는 애플리케이션 및 라이브러리의 내부 구현에서 가장 자주 사용됩니다. 특수 컬렉션은 주로 API(속성 및 매개 변수 형식)에 노출됩니다.
✔️ IDictionary
또는 IDictionary<TKey,TValue>
를 구현하는 추상화의 이름에는 반드시 "딕셔너리" 접미사를 사용하세요.
✔️ 목록을 나타내는 IEnumerable
(또는 그 하위 항목)을 구현하는 형식의 이름에는 "컬렉션" 접미사를 사용하십시오.
✔️ 사용자 지정 데이터 구조에 적절한 데이터 구조 이름을 사용합니다.
❌ 컬렉션 추상화의 이름으로 "LinkedList" 또는 "Hashtable"과 같은 특정 구현을 의미하는 접미사를 사용하지 마세요.
✔️ 컬렉션 이름 앞에 항목 유형의 이름을 붙이는 것을 고려하세요. 예를 들어 형식 Address
(구현 IEnumerable<Address>
)의 항목을 저장하는 컬렉션의 이름을 지정 AddressCollection
해야 합니다. 항목 형식이 인터페이스인 경우 항목 형식의 "I" 접두사를 생략할 수 있습니다. 따라서 IDisposable 항목의 모음을 DisposableCollection
라고 부를 수 있습니다.
✔️ 해당 쓰기 가능한 컬렉션이 추가되거나 프레임워크에 이미 있는 경우 읽기 전용 컬렉션 이름에 "ReadOnly" 접두사를 사용하는 것이 좋습니다.
예를 들어 문자열의 읽기 전용 컬렉션을 호출 ReadOnlyStringCollection
해야 합니다.
Microsoft Corporation의 일부 저작권 2005, 2009. 모든 권리 보유.
프레임워크 디자인 지침에서 Pearson Education, Inc.의 권한으로 재인쇄 : 재사용 가능한 .NET 라이브러리에 대한 규칙, 관용구 및 패턴, Krzysztof Cwalina 및 Brad Abrams의 제2판, Microsoft Windows 개발 시리즈의 일환으로 Addison-Wesley Professional이 2008년 10월 22일 출판했습니다.