내 공개 API 메서드 및 속성에서 반환해야하는 컬렉션 유형에 대해 혼란스러워합니다.
제가 염두에두고있는 컬렉션은 IList
, ICollection
및 Collection
입니다.
이러한 유형 중 하나를 항상 다른 유형보다 선호합니까, 아니면 특정 상황에 따라 달라 집니까?
내 공개 API 메서드 및 속성에서 반환해야하는 컬렉션 유형에 대해 혼란스러워합니다.
제가 염두에두고있는 컬렉션은 IList
, ICollection
및 Collection
입니다.
이러한 유형 중 하나를 항상 다른 유형보다 선호합니까, 아니면 특정 상황에 따라 달라 집니까?
답변:
일반적으로 가능한 한 일반적인 유형, 즉 소비자가 사용해야하는 반환 된 데이터를 충분히 알고있는 유형을 반환해야합니다. 이렇게하면 API를 사용하는 코드를 손상시키지 않고 API 구현을 자유롭게 변경할 수 있습니다.
IEnumerable<T>
인터페이스도 반환 유형으로 고려하십시오 . 결과가 반복 될 경우 소비자는 그 이상을 필요로하지 않습니다.
Count
메서드 구현은 컬렉션의 실제 유형을 확인하므로 배열과 같은 일부 알려진 유형에 대해 Length
또는 Count
속성을 사용 ICollection
하며 IEnumerable
.
Thing<T>
구현 IList<T>
하지 않고 구현 하면 a ICollection
를 호출 IEnumerable<Cat>.Count()
하는 Thing<Cat>
것은 빠르지 만 호출 IEnumerable<Animal>.Count()
은 느릴 것입니다 (확장 메서드가 다음의 구현을 찾고 찾지 못하기 때문에). ICollection<Cat>
). 클래스 구현하는 제네릭이 아닌 경우에는 ICollection
, 그러나, IEnumerable<Animal>.Count
찾아 사용하는 것입니다.
ICollection<T>
같은 수집 의미를 노출시키는 인터페이스는 Add()
, Remove()
, 및 Count
.
Collection<T>
ICollection<T>
인터페이스 의 구체적인 구현입니다 .
IList<T>
본질적 ICollection<T>
으로 무작위 주문 기반 액세스입니다.
이 경우 결과에 순서 기반 인덱싱 (다음 사용 IList<T>
) 과 같은 목록 의미론이 필요한지 여부 또는 정렬되지 않은 결과 "백"을 반환해야하는지 (다음 사용 )를 결정해야합니다 ICollection<T>
.
Collection<T>
구현 IList<T>
및뿐만 아니라 ICollection<T>
.
IEnumerable<T>
정렬됩니다. 어떤 구별 IList<T>
에서 것은 ICollection<T>
이 인덱스 작업에 구성원을 제공하는 것입니다. 예를 들어 list[5]
작동하지만 collection[5]
컴파일되지 않습니다.
IList<T>
. 그렇지 않은 주문 된 컬렉션이 많이 있습니다. IList<T>
빠른 인덱스 액세스에 관한 것입니다.
IEnumerable<T>
주문됩니까? Take- HashSet<T>
구현 IEnumerable<T>
되지만 명확하게 주문되지 않았습니다. 즉, 항목의 순서에 영향을 미치지 않으며 내부 해시 테이블이 재구성되는 경우이 순서는 언제든지 변경 될 수 있습니다.
주요 차이점 IList<T>
및 ICollection<T>
즉 IList<T>
인덱스를 통해 액세스 요소로 할 수 있습니다. IList<T>
배열과 유사한 유형을 설명합니다. 의 요소는 ICollection<T>
열거를 통해서만 액세스 할 수 있습니다. 둘 다 요소의 삽입 및 삭제를 허용합니다.
컬렉션을 열거하기 만하면되는 IEnumerable<T>
경우 선호됩니다. 다른 것보다 두 가지 장점이 있습니다.
컬렉션에 대한 변경을 허용하지 않습니다 (참조 유형 인 경우 요소에는 변경할 수 없음).
알고리즘 적으로 생성되고 전혀 컬렉션이 아닌 열거를 포함하여 가능한 가장 다양한 소스를 허용합니다.
Collection<T>
주로 컬렉션 구현 자에게 유용한 기본 클래스입니다. 인터페이스 (API)에 노출하면 파생되지 않은 많은 유용한 컬렉션이 제외됩니다.
의 한 가지 단점은 IList<T>
배열이이를 구현하지만 항목을 추가하거나 제거 할 수 없다는 것입니다 (즉, 배열 길이를 변경할 수 없음). IList<T>.Add(item)
배열 을 호출하면 예외가 발생합니다 . 이를 시도하기 전에 확인할 수 IList<T>
있는 부울 속성 IsReadOnly
이 있기 때문에 상황은 다소 혼란 스럽습니다 . 하지만 제 눈에는 이것은 여전히 라이브러리의 디자인 결함입니다 . 따라서 List<T>
항목을 추가하거나 제거 할 수있는 가능성이 필요할 때 직접 사용 합니다.
Collection
, ReadOnlyCollection
또는 KeyedCollection
. 그리고 그것은 List
반환되지 않아야합니다.
IList<T>
배열을 매개 변수로 사용하여 메서드가 호출되지 않도록 할 방법이 없습니다.
IList<T>
모든 일반 목록의 기본 인터페이스입니다. 정렬 된 컬렉션이므로 구현시 정렬 된 순서에서 삽입 순서에 이르기까지 순서를 결정할 수 있습니다. 또한 Ilist
메서드가 인덱스를 기반으로 목록의 항목을 읽고 편집 할 수 있도록하는 Item 속성이 있습니다. 이를 통해 위치 인덱스의 목록에 값을 삽입하거나 제거 할 수 있습니다.
또한 IList<T> : ICollection<T>
에서의 모든 메소드를 ICollection<T>
여기에서 구현할 수도 있습니다.
ICollection<T>
모든 일반 컬렉션에 대한 기본 인터페이스입니다. 크기, 열거 자 및 동기화 방법을 정의합니다. 컬렉션에 항목을 추가하거나 제거 할 수 있지만 인덱스 속성이 없어서 발생하는 위치는 선택할 수 없습니다.
Collection<T>
에 대한 구현을 제공 IList<T>
, IList
하고 IReadOnlyList<T>
.
ICollection<T>
대신 보다 좁은 인터페이스 유형을 사용하는 경우 IList<T>
변경 사항이 깨지지 않도록 코드를 보호 할 수 있습니다. 와 같이 더 넓은 인터페이스 유형을 사용하면 IList<T>
코드 변경이 중단 될 위험이 더 커집니다.
출처 에서 인용 ,
ICollection
,ICollection<T>
: 컬렉션을 수정하거나 크기에 관심이 있습니다.IList
,IList<T>
: 컬렉션을 수정하고 싶고 컬렉션에서 요소의 순서 및 / 또는 위치에 관심이 있습니다.
인터페이스 유형을 반환하는 것이 더 일반적이므로 (특정 사용 사례에 대한 추가 정보가 부족함) 그것에 의지하고 싶습니다. 인덱싱 지원을 노출하려면을 선택하십시오 IList<T>
. 그렇지 않으면 ICollection<T>
충분합니다. 마지막으로, 반환 된 유형이 읽기 전용임을 나타내려면을 선택합니다 IEnumerable<T>
.
이전에 읽지 않은 경우를 대비하여 Brad Abrams와 Krzysztof Cwalina는 "프레임 워크 디자인 지침 : 재사용 가능한 .NET 라이브러리에 대한 규칙, 관용구 및 패턴"이라는 제목의 훌륭한 책을 썼습니다 ( 여기 에서 요약을 다운로드 할 수 있음 ).
IEnumerable<T>
읽기 전용입니까? 물론 저장소 컨텍스트에서 다시 튜닝 할 때 ToList를 실행 한 후에도 스레드로부터 안전하지 않습니다. 문제는 원래 데이터 소스가 GC를 가져 오면 IEnumarble.ToList ()가 다중 스레드 컨텍스트에서 작동하지 않는다는 것입니다. 작업을 수행 한 후 GC가 호출되기 때문에 선형에서 작동하지만 async
이제 4.5+ IE에서 며칠을 사용 하는 것은 공 통증이되고 있습니다.
이 질문에서 나온 몇 가지 주제가 있습니다.
객체 지향 API 임을 강조하고 싶을 수 있습니다.
인터페이스 대 클래스
인터페이스에 대한 경험이 많지 않다면 수업을 고수하는 것이 좋습니다. 필자는 많은 개발자들이 인터페이스로 뛰어 드는 것을 봅니다. 비록 그것이 필요하지 않더라도 말입니다.
그리고 결국에는 좋은 인터페이스 디자인으로 마이그레이션 할 수있는 좋은 클래스 디자인 대신 열악한 인터페이스 디자인을 끝내십시오.
API에서 많은 인터페이스를 볼 수 있지만 필요하지 않다면 서두르지 마십시오.
결국 코드에 인터페이스를 적용하는 방법을 배우게됩니다.
여러 클래스, 컬렉션, 목록, 배열에서 특정 클래스는 무엇입니까?
C # (dotnet)에는 상호 교환 할 수있는 여러 클래스가 있습니다. 이미 언급했듯이 "CanBeSortedClass"와 같은보다 구체적인 클래스의 항목이 필요한 경우 API에서 명시 적으로 지정하십시오.
API 사용자가 클래스를 정렬 할 수 있는지, 아니면 요소에 일부 형식을 적용 할 수 있는지 정말 알아야합니까? 그런 다음 "CanBeSortedClass"또는 "ElementsCanBePaintedClass"를 사용하고, 그렇지 않으면 "GenericBrandClass"를 사용하십시오.
그렇지 않으면 더 일반적인 클래스를 사용하십시오.
공통 컬렉션 클래스 대 하위 항목 ( "제네릭") 컬렉션
다른 요소를 포함하는 클래스가 있으며 모든 요소가 특정 유형이어야 함을 지정할 수 있습니다.
일반 컬렉션 은 다음과 같이 새 컬렉션을 만들지 않고도 여러 코드 응용 프로그램에 대해 동일한 컬렉션을 사용할 수있는 클래스입니다. 컬렉션 .
API 사용자가 모든 요소에 대해 동일한 매우 구체적인 유형이 필요합니까?
같은 것을 사용하십시오 List<WashingtonApple>
.
API 사용자에게 몇 가지 관련 유형이 필요합니까?
노출 List<Fruit>
당신의 API를 들어, 및 사용 List<Orange>
List<Banana>
, List<Strawberry>
내부, 어디서 Orange
, Banana
그리고 Strawberry
후손이다 Fruit
.
API 사용자에게 일반 유형 컬렉션이 필요합니까?
를 사용하여 List
모든 항목은, object
(들).
건배.