코드는 다음과 같습니다.
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>
복사 된 항목 목록이 될 것입니다.