'IList'대 'ICollection'대 'Collection'반환


119

내 공개 API 메서드 및 속성에서 반환해야하는 컬렉션 유형에 대해 혼란스러워합니다.

제가 염두에두고있는 컬렉션은 IList, ICollectionCollection입니다.

이러한 유형 중 하나를 항상 다른 유형보다 선호합니까, 아니면 특정 상황에 따라 달라 집니까?



답변:


71

일반적으로 가능한 한 일반적인 유형, 즉 소비자가 사용해야하는 반환 된 데이터를 충분히 알고있는 유형을 반환해야합니다. 이렇게하면 API를 사용하는 코드를 손상시키지 않고 API 구현을 자유롭게 변경할 수 있습니다.

IEnumerable<T>인터페이스도 반환 유형으로 고려하십시오 . 결과가 반복 될 경우 소비자는 그 이상을 필요로하지 않습니다.


25
또한 Count 속성을 포함한 추가 유틸리티를 제공하기 위해 IEnumerable <T>를 확장하는 ICollection <T>도 고려하십시오. 시퀀스를 여러 번 탐색하지 않고도 시퀀스의 길이를 결정할 수 있기 때문에 유용 할 수 있습니다.
retrodrone 2013

11
@retrodrone : 실제로 Count메서드 구현은 컬렉션의 실제 유형을 확인하므로 배열과 같은 일부 알려진 유형에 대해 Length또는 Count속성을 사용 ICollection하며 IEnumerable.
Guffa 2013

8
@Guffa : 클래스 가 non-generic을 Thing<T>구현 IList<T>하지 않고 구현 하면 a ICollection를 호출 IEnumerable<Cat>.Count()하는 Thing<Cat>것은 빠르지 만 호출 IEnumerable<Animal>.Count()은 느릴 것입니다 (확장 메서드가 다음의 구현을 찾고 찾지 못하기 때문에). ICollection<Cat>). 클래스 구현하는 제네릭이 아닌 경우에는 ICollection, 그러나, IEnumerable<Animal>.Count찾아 사용하는 것입니다.
supercat 2013-04-11


8
동의하지 않습니다. 클라이언트가 원하는 경우 직접 사용할 수 있도록 보유한 가장 풍부한 유형을 반환하는 것이 가장 좋습니다. List <>가있는 경우 호출자가 ToList ()를 불필요하게 호출하도록 강제하기 위해 IEnuerable <> 만 반환하는 이유는 무엇입니까?
zumalifeguard

140

ICollection<T>같은 수집 의미를 노출시키는 인터페이스는 Add(), Remove(), 및 Count.

Collection<T>ICollection<T>인터페이스 의 구체적인 구현입니다 .

IList<T>본질적 ICollection<T>으로 무작위 주문 기반 액세스입니다.

이 경우 결과에 순서 기반 인덱싱 (다음 사용 IList<T>) 과 같은 목록 의미론이 필요한지 여부 또는 정렬되지 않은 결과 "백"을 반환해야하는지 (다음 사용 )를 결정해야합니다 ICollection<T>.


5
Collection<T>구현 IList<T>및뿐만 아니라 ICollection<T>.
CodesInChaos 2012 년

56
.Net의 모든 컬렉션은 정렬되어 있기 때문에 IEnumerable<T>정렬됩니다. 어떤 구별 IList<T>에서 것은 ICollection<T>이 인덱스 작업에 구성원을 제공하는 것입니다. 예를 들어 list[5]작동하지만 collection[5]컴파일되지 않습니다.
svick

5
나는 또한 주문 된 컬렉션이 구현되어야한다는 것에 동의하지 않습니다 IList<T>. 그렇지 않은 주문 된 컬렉션이 많이 있습니다. IList<T>빠른 인덱스 액세스에 관한 것입니다.
CodesInChaos 2012 년

4
@yoyo .net 컬렉션 클래스와 인터페이스는 단순히 잘못 설계되고 이름이 잘못되었습니다. 나는 그들이 왜 그렇게 이름을 지 었는지에 대해 너무 많이 생각하지 않을 것입니다.
CodesInChaos

6
@svick : 모든 컬렉션이 주문 되었기 때문에 IEnumerable<T>주문됩니까? Take- HashSet<T>구현 IEnumerable<T>되지만 명확하게 주문되지 않았습니다. 즉, 항목의 순서에 영향을 미치지 않으며 내부 해시 테이블이 재구성되는 경우이 순서는 언제든지 변경 될 수 있습니다.
Olivier Jacot-Descombes 2015

61

주요 차이점 IList<T>ICollection<T>IList<T>인덱스를 통해 액세스 요소로 할 수 있습니다. IList<T>배열과 유사한 유형을 설명합니다. 의 요소는 ICollection<T>열거를 통해서만 액세스 할 수 있습니다. 둘 다 요소의 삽입 및 삭제를 허용합니다.

컬렉션을 열거하기 만하면되는 IEnumerable<T>경우 선호됩니다. 다른 것보다 두 가지 장점이 있습니다.

  1. 컬렉션에 대한 변경을 허용하지 않습니다 (참조 유형 인 경우 요소에는 변경할 수 없음).

  2. 알고리즘 적으로 생성되고 전혀 컬렉션이 아닌 열거를 포함하여 가능한 가장 다양한 소스를 허용합니다.

Collection<T>주로 컬렉션 구현 자에게 유용한 기본 클래스입니다. 인터페이스 (API)에 노출하면 파생되지 않은 많은 유용한 컬렉션이 제외됩니다.


의 한 가지 단점은 IList<T>배열이이를 구현하지만 항목을 추가하거나 제거 할 수 없다는 것입니다 (즉, 배열 길이를 변경할 수 없음). IList<T>.Add(item)배열 을 호출하면 예외가 발생합니다 . 이를 시도하기 전에 확인할 수 IList<T>있는 부울 속성 IsReadOnly이 있기 때문에 상황은 다소 혼란 스럽습니다 . 하지만 제 눈에는 이것은 여전히 ​​라이브러리의 디자인 결함입니다 . 따라서 List<T>항목을 추가하거나 제거 할 수있는 가능성이 필요할 때 직접 사용 합니다.


코드 분석 (와의 FxCop)의 조언 : 콘크리트 일반적인 집합을 반환 할 때, 다음 중 하나가 반환되어야한다는 Collection, ReadOnlyCollection또는 KeyedCollection. 그리고 그것은 List반환되지 않아야합니다.
DavidRR

@DavidRR : 종종 항목을 추가하거나 제거해야하는 메소드에 목록을 전달하는 것이 유용합니다. 매개 변수를로 입력하면 IList<T>배열을 매개 변수로 사용하여 메서드가 호출되지 않도록 할 방법이 없습니다.
Olivier Jacot-Descombes

7

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>: 컬렉션을 수정하고 싶고 컬렉션에서 요소의 순서 및 / 또는 위치에 관심이 있습니다.


5

인터페이스 유형을 반환하는 것이 더 일반적이므로 (특정 사용 사례에 대한 추가 정보가 부족함) 그것에 의지하고 싶습니다. 인덱싱 지원을 노출하려면을 선택하십시오 IList<T>. 그렇지 않으면 ICollection<T>충분합니다. 마지막으로, 반환 된 유형이 읽기 전용임을 나타내려면을 선택합니다 IEnumerable<T>.

이전에 읽지 않은 경우를 대비하여 Brad Abrams와 Krzysztof Cwalina는 "프레임 워크 디자인 지침 : 재사용 가능한 .NET 라이브러리에 대한 규칙, 관용구 및 패턴"이라는 제목의 훌륭한 책을 썼습니다 ( 여기 에서 요약을 다운로드 할 수 있음 ).


IEnumerable<T>읽기 전용입니까? 물론 저장소 컨텍스트에서 다시 튜닝 할 때 ToList를 실행 한 후에도 스레드로부터 안전하지 않습니다. 문제는 원래 데이터 소스가 GC를 가져 오면 IEnumarble.ToList ()가 다중 스레드 컨텍스트에서 작동하지 않는다는 것입니다. 작업을 수행 한 후 GC가 호출되기 때문에 선형에서 작동하지만 async이제 4.5+ IE에서 며칠을 사용 하는 것은 공 통증이되고 있습니다.
Piotr Kula

-3

이 질문에서 나온 몇 가지 주제가 있습니다.

  • 인터페이스 대 클래스
  • 여러 클래스, 컬렉션, 목록, 배열에서 특정 클래스는 무엇입니까?
  • 공통 클래스 대 하위 항목 ( "제네릭") 컬렉션

객체 지향 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(들).

건배.


7
"인터페이스에 대한 경험이 많지 않다면 수업을 계속하는 것이 좋습니다."이것은 좋은 조언이 아닙니다. 그것은 당신이 모르는 것이 있으면 멀리 떨어져있는 것과 같다. 인터페이스는 매우 강력하며 "추상화 대 구체화에 대한 프로그램"개념을 뒷받침합니다. 또한 모의를 통해 유형을 교환 할 수 있기 때문에 단위 테스트를 수행하는 데에도 매우 강력합니다. 이 주석 외에도 인터페이스를 사용하는 다른 많은 이유가 있으므로 반드시 탐색하십시오.
atconway 2013

@atconway 나는 정기적으로 인터페이스를 사용하지만 많은 개념과 마찬가지로 강력한 도구이므로 쉽게 혼합하여 사용할 수 있습니다. 때로는 개발자가 필요하지 않을 수도 있습니다. 내 제안은 "인터페이스 금지"가 아니었고 "이 경우에는 인터페이스를 건너 뛸 수 있습니다. 이에 대해 배우면 나중에 최대한 활용할 수 있습니다"라는 제안이었습니다. 건배.
umlcat 2013

1
항상 인터페이스로 프로그래밍하는 것이 좋습니다. 코드를 느슨하게 결합하는 데 도움이됩니다.
mac10688 2014

@ mac10688 이전 답변 (atconway)도 귀하의 의견에 적용됩니다.
umlcat 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.