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

코드는 다음과 같습니다.

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’변경

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



답변

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

미래 보장

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

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

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

API 단순성

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

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


답변

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


답변

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

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

공개 배열이있는 경우 예 :

public int[] MyIntegers { get; }

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

someObject.MyIngegers[3] = 12345;

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


답변

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

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

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

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


답변

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


답변

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

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

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


답변

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

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

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

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