Collection <T> 대 List <T> 인터페이스에서 무엇을 사용해야합니까?


162

코드는 다음과 같습니다.

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

코드 분석을 실행하면 다음 권장 사항이 나타납니다.

경고 3 CA1002 : Microsoft.Design : Collection, ReadOnlyCollection 또는 KeyedCollection을 사용하도록 'IMyClass.GetList ()'에서 'List'변경

이 문제를 어떻게 해결해야하며 여기에서 좋은 방법은 무엇입니까?

답변:


234

왜 그렇지 않은지에 대한 질문의 "왜"부분에 대답하기 위해 List<T>, 그 이유는 미래 보장 및 API 단순성입니다.

미래 보장

List<T>서브 클래 싱으로 쉽게 확장 할 수 있도록 설계되지 않았습니다. 내부 구현에 적합하도록 설계되었습니다. 그 메소드가 가상이 아니므로 재정의 할 수 없으며 Add/ Insert/ Remove작업 에 대한 후크가 없다는 것을 알 수 있습니다 .

이는 나중에 컬렉션의 동작을 변경해야하는 경우 (예 : 사람들이 추가하려고하는 null 객체를 거부하거나 클래스 상태 업데이트와 같은 경우 추가 작업을 수행하려는 경우) 유형을 변경해야 함을 의미합니다. 컬렉션의 당신은 당신이 서브 클래스 할 수있는 것으로 돌아갑니다. 인터 클래스 변경이 될 것입니다 (물론 null을 허용하지 않는 것과 같은 의미를 변경하는 것도 인터페이스 변경 일 수도 있지만 내부 클래스 상태를 업데이트하는 것은 아닙니다).

그러니 쉽게 등의 서브 클래스 수있는 클래스 반환하여 Collection<T>같은 인터페이스 또는 IList<T>, ICollection<T>또는 IEnumerable<T>이 여전히 반환 할 수 있기 때문에 소비자의 코드를 파괴하지 않고, 당신이 당신의 요구를 충족하기 위해 다른 콜렉션 유형을로 내부 구현을 변경할 수 있습니다 그들이 기대하는 유형.

API 단순성

List<T>같은 유용한 작업을 많이 포함하고 BinarySearch, Sort등등을. 그러나 이것이 콜렉션 인 경우 소비자가 아닌 목록의 의미를 제어 할 가능성이 있습니다. 따라서 클래스 내부에서 이러한 작업이 필요할 수 있지만 클래스의 소비자가 호출하기를 원치 않을 수도 있습니다.

따라서 더 간단한 콜렉션 클래스 또는 인터페이스를 제공하여 API 사용자가 보는 멤버 수를 줄이고 사용하기가 더 쉽습니다.


1
이 응답은 끝났습니다. 주제에 대한 또 다른 좋은 읽을
— 거리는

7
첫 번째 요점을 볼 수 있지만 API 단순성 부분에 동의하는지 모르겠습니다.
— 보리스 칼 렌스

stackoverflow.com/a/398988/2632991 Collections와 Lists의 차이점에 대한 실제 게시물도 있습니다.
— El Mac

2
blogs.msdn.com/fxcop/archive/2006/04/27/…- > 죽었습니다. 이에 대한 최신 정보가 있습니까?
— Machado


50

구체적인 컬렉션이 아닌 인터페이스를 반환하도록 개인적으로 선언합니다. 정말로 목록 액세스를 원하면을 사용하십시오 IList<T>. 그렇지 않으면, 생각 ICollection<T>하고 IEnumerable<T>.


1
그러면 IList가 ICollection 인터페이스를 확장합니까?
— bovium

8
@ 존 : 나는 이것이 오래되었다는 것을 알고 있지만 blogs.msdn.com/b/kcwalina/archive/2005/09/26/474010.aspx 에서 Krzysztof의 말에 대해 언급 할 수 있습니까? 특히 그의 의견 We recommend using Collection<T>, ReadOnlyCollection<T>, or KeyedCollection<TKey,TItem> for outputs and properties and interfaces IEnumerable<T>, ICollection<T>, IList<T> for inputs. CA1002는 Krzysztof의 의견과 일치하는 것으로 보입니다. 인터페이스 대신에 구체적인 컬렉션이 권장되는 이유와 입력 / 출력의 차이점을 상상할 수 없습니다.
— Nelson Rothermel

3
@Nelson : 호출자가 불변리스트를 전달 하도록 요구 하는 경우는 드물지만 , 불변리스트를 반환 하도록하는 것이 합리적 입니다. 그래도 다른 컬렉션에 대해서는 확실하지 않습니다. 더 자세하게 설명해 드리겠습니다.
— Jon Skeet

2
특정한 경우가 아닙니다. 분명히 일반적으로 ReadOnlyCollection<T>입력에는 의미가 없습니다. 마찬가지로 IList<T>입력에 따르면 출력에 의미가없는 "Sort () 또는 IList에있는 다른 멤버가 필요합니다"라고 말합니다. 그러나 내가 의미 ICollection<T>하는 바는 입력 및 Collection<T>출력 으로 권장되는 이유입니다 . 왜 하지 사용 ICollection<T>이 제안 또한 출력으로?
— Nelson Rothermel

9
나는 그것이 모호성과 관련이 있다고 생각합니다. Collection<T>그리고 ReadOnlyCollection<T>둘 다에서 파생됩니다 ICollection<T>(즉, 없습니다 IReadOnlyCollection<T>). 인터페이스를 반환하면 어떤 인터페이스인지, 수정할 수 있는지 확실하지 않습니다. 어쨌든, 귀하의 의견에 감사드립니다. 이것은 좋은 위생 검사였습니다.
— Nelson Rothermel

3

아직 아무도 왜 "왜"에 대답하지 않았다고 생각합니다. a Collection<T>대신 "왜"를 사용해야하는 List<T>이유는를 노출하면 List<T>객체에 액세스 할 수있는 모든 사람이 목록의 항목을 수정할 수 있기 때문 입니다. 반면 Collection<T>에 "Add (추가)", "Remove (제거)"등의 방법을 만들고 있음을 나타냅니다.

당신은 아마 당신 자신을 위해 (또는 아마도 몇 명의 동료를 위해) 인터페이스를 코딩하고 있기 때문에 걱정할 필요가 없습니다. 이해가 될만한 또 다른 예가 있습니다.

공개 배열이있는 경우 예 :

public int[] MyIntegers { get; }

아무도 값을 엉망으로 만들 수없는 "get"접근자가 있기 때문에 사실이 아니라고 생각할 것입니다. 누구나 다음과 같이 내부의 값을 변경할 수 있습니다.

someObject.MyIngegers[3] = 12345;

개인적 List<T>으로 대부분의 경우에 사용합니다. 그러나 임의의 개발자에게 제공 할 클래스 라이브러리를 디자인하고 객체의 상태에 의존 해야하는 경우 자신의 컬렉션을 만들고 거기에서 잠그고 싶을 것입니다. )


"클라이언트 코드에 List <T>를 반환하면 클라이언트 코드가 컬렉션을 수정할 때 알림을받을 수 없습니다." - FX의 COP는 ... 또한 "을 참조하십시오 msdn.microsoft.com/en-us/library/0fss9skc.aspx 와우, 나는 모든 : 후 기본 떨어져 아니에요 것 같다 ..."
— 디모데 Khouri을

와우-몇 년 후 위의 주석에 붙여 넣은 링크의 끝에 인용 부호가 있었으므로 작동하지 않았습니다 ... msdn.microsoft.com/en-us/library/0fss9skc.aspx
— Timothy Khouri

2

List 객체를 직접 조작하는 대신 노출을 직접 추상화하는 것입니다.

다른 객체 (또는 사람)가 객체의 상태를 직접 수정하도록하는 것은 좋지 않습니다. 부동산 게터 / 세터를 생각하십시오.

컬렉션-> 일반 컬렉션의 경우
ReadOnlyCollection-> 수정하지 않아야하는 컬렉션의 경우
KeyedCollection-> 사전을 대신 사용하려는 경우.

이 문제를 해결하는 방법은 클래스에서 수행하려는 작업과 GetList () 메서드의 목적에 따라 다릅니다. 정교하게 할 수 있습니까?


1
그러나 Collection <T> 및 KeyedCollection <,>도 읽기 전용이 아닙니다.
— nawfal

@nawfal 그리고 나는 그것이 어디에 있다고 말했습니까?
— chakrit

1
당신은 상태가 다른 개체 (또는 사람)의 오브젝트에 직접의 상태를 수정할 수 없습니다 및 목록 3 수집 유형. ReadOnlyCollection다른 두 사람을 금지 하는 것은 그것을 따르지 않습니다.
— nawfal

그것은 "좋은 습관"을 의미합니다. 적절한 맥락으로 부탁드립니다. OP가 경고를 이해하기를 원하기 때문에 아래의 목록에는 이러한 유형의 기본 요구 사항이 나와 있습니다. 그런 다음 계속 GetList()해서 더 정확하게 도울 수 있는 목적에 대해 물어 보았습니다.
— chakrit

1
좋아, 나는 그 부분을 이해한다. 그러나 여전히 추론 부분은 나에 따르면 소리가 아닙니다. 당신은 말할 Collection<T>내부 구현을 추상화하는 데 도움이 내부 목록을 직접 조작을 방지 할 수 있습니다. 어떻게? Collection<T>전달 된 동일한 인스턴스에서 작동하는 랩퍼 일뿐입니다. 상속을위한 동적 컬렉션이지만 다른 것은 없습니다 (Greg의 답변이 더 관련이 있습니다).
— nawfal

1

이런 종류의 경우에는 보통 필요한 최소한의 구현을 노출하려고합니다. 소비자가 실제로 목록을 사용하고 있음을 알 필요가 없으면 목록을 반환 할 필요가 없습니다. Microsoft가 컬렉션을 제안함에 따라 반환하면 클래스 소비자로부터 목록을 사용하고 있다는 사실을 숨기고 내부 변경으로부터 격리시킵니다.


1

이 요청 이후 오랜 시간이 지났지 만 추가해야 할 것이 있습니다.

목록 유형이에서 List<T>대신 파생되는 Collection<T>경우 구현되는 보호 된 가상 메소드를 Collection<T>구현할 수 없습니다 . 이것은 목록을 수정 한 경우 파생 된 유형이 응답 할 수 없음을 의미합니다. List<T>항목을 추가하거나 제거 할 때 사용자가 알고 있다고 가정 하기 때문 입니다. 알림에 응답 할 수있는 것은 오버 헤드이므로 List<T>제공하지 않습니다.

외부 코드가 컬렉션에 액세스 할 수있는 경우 항목을 추가하거나 제거 할시기를 제어하지 못할 수 있습니다. 따라서 Collection<T>목록이 수정 된시기를 알 수있는 방법을 제공합니다.


0

다음과 같은 것을 반환하는 데 아무런 문제가 없습니다.

this.InternalData.Filter(crteria).ToList();

연결이 끊긴 내부 데이터 복사본 을 반환 하거나 데이터 쿼리 결과를 분리 한 경우 List<TItem>구현 세부 정보를 노출하지 않고 안전하게 반환 할 수 있으며 반환 된 데이터를 편리한 방식으로 사용할 수 있습니다.

그러나 이것은 내가 기대하는 소비자 유형에 달려 있습니다. 이것이 데이터 그리드와 같은 경우 대부분의 경우 IEnumerable<TItem> 복사 된 항목 목록이 될 것입니다.


-1

Collection 클래스는 실제로 다른 컬렉션 주위의 래퍼 클래스이므로 구현 세부 정보 및 기타 기능을 숨길 수 있습니다. 나는 이것이 객체 지향 언어의 코딩 패턴 숨기기 속성과 관련이 있다고 생각합니다.

걱정하지 않아도된다고 생각하지만 실제로 코드 분석 도구를 사용하려면 다음을 수행하십시오.

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);

1
죄송합니다. 오타였습니다. Collection <MyClass>를 언급합니다. 나는 C # 4와 일반 공분산 btw에 손을 대길 정말로 기대합니다!
— Tamas Czinege

Collection<T>내가 보호 하는 한 포장지 자체는 그 자체도 물론 기본 수집 물도 보호하지 않습니다.
— nawfal

그 코드는 "코드 분석 도구를 만족 시키십시오". @TamasCzinege가 사용 Collection<T>하면 즉시 기본 컬렉션을 보호 한다고 말하지 않습니다 .
— chakrit
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.