[C#] List <T> 또는 IList <T> [닫힘]

누구나 C #에서 List over IList를 사용하려는 이유를 설명 할 수 있습니까?

관련 질문 : 노출이 나쁜 이유는 무엇입니까?List<T>



답변

다른 사람들이 사용할 라이브러리를 통해 클래스를 공개하는 경우 일반적으로 구체적인 구현이 아닌 인터페이스를 통해 클래스를 공개하려고합니다. 나중에 다른 구체적인 클래스를 사용하도록 클래스 구현을 변경하기로 결정한 경우 도움이됩니다. 이 경우 인터페이스가 변경되지 않으므로 라이브러리의 사용자가 코드를 업데이트 할 필요가 없습니다.

내부에서 사용하는 경우에는 그다지 신경 쓰지 않을 List<T>수 있으며 사용하는 것이 좋습니다.


답변

덜 인기있는 대답은 프로그래머가 소프트웨어를 전 세계적으로 재사용하는 척하는 것입니다. 실제로 대다수의 프로젝트가 소수의 사람들에 의해 유지되지만 멋진 인터페이스 관련 사운드 비트가 있으면 대단합니다. 당신 자신.

건축 우주 비행사 . 이미 .NET 프레임 워크에있는 항목에 추가하는 고유 한 IList를 작성할 가능성은 너무 멀기 때문에 “모범 사례”를 위해 예약 된 이론적 인 젤리 토트입니다.

소프트웨어 우주 비행사

인터뷰에서 어떤 것을 사용 하느냐는 질문이 있다면 IList라고 말하고 미소를 지으며 둘 다 자신이 너무 영리하다는 것을 기쁘게 생각합니다. 또는 공개 API, IList. 잘만되면 당신은 나의 요점을 얻는다.


답변

인터페이스는 약속 (또는 계약)입니다.

항상 약속과 함께- 작을수록 좋습니다 .


답변

어떤 사람들은 “항상” IList<T>대신 “을 사용 합니다 List<T>.
그들은 당신이에서 메소드 서명을 변경하려면 void Foo(List<T> input)void Foo(IList<T> input).

이 사람들은 틀 렸습니다.

그것보다 미묘한 차이가 있습니다. IList<T>공용 인터페이스의 일부로 라이브러리에 반환하는 경우 향후 사용자 지정 목록을 만들 수있는 흥미로운 옵션이 있습니다. 해당 옵션이 필요하지는 않지만 논쟁의 여지가 있습니다. 구체적인 유형 대신 인터페이스를 반환하는 것이 전체 주장이라고 생각합니다. 언급 할 가치가 있지만이 경우 심각한 결함이 있습니다.

사소한 반론으로, 모든 발신자가 List<T>어쨌든 필요하다는 것을 알 수 있으며 호출 코드는.ToList()

그러나 훨씬 더 중요한 것은, 당신은 매개 변수로 IList에 동의하는 경우 때문에 당신은 더 나은 조심 것 IList<T>List<T>같은 방식으로 작동하지 않습니다. 이름의 유사성에도 불구하고 인터페이스 공유에도 불구하고 동일한 계약을 공개 하지 않습니다 .

이 방법이 있다고 가정하십시오.

public Foo(List<int> a)
{
    a.Add(someNumber);
}

도움이되는 동료가 받아 들일 방법을 “리팩터링”합니다 IList<int>.

int[]구현 하기 때문에 코드가 손상 IList<int>되었지만 크기는 고정되어 있습니다. 에 대한 계약 ICollection<T>(의베이스 IList<T>)를 확인하는 데 사용하는 코드가 필요합니다 IsReadOnly컬렉션에서 항목을 추가하거나 제거하기 전에 플래그. 계약은 List<T>그렇지 않습니다.

Liskov 대체 원칙 (간체)에는 추가 전제 조건이나 사후 조건없이 파생 유형을 기본 유형 대신 사용할 수 있어야한다고 명시되어 있습니다.

이것은 Liskov 대체 원칙을 어기는 것 같습니다.

 int[] array = new[] {1, 2, 3};
 IList<int> ilist = array;

 ilist.Add(4); // throws System.NotSupportedException
 ilist.Insert(0, 0); // throws System.NotSupportedException
 ilist.Remove(3); // throws System.NotSupportedException
 ilist.RemoveAt(0); // throws System.NotSupportedException

그러나 그렇지 않습니다. 이에 대한 대답은 예제에서 IList <T> / ICollection <T>을 잘못 사용했다는 것입니다. ICollection <T>를 사용하는 경우 IsReadOnly 플래그를 확인해야합니다.

if (!ilist.IsReadOnly)
{
   ilist.Add(4);
   ilist.Insert(0, 0);
   ilist.Remove(3);
   ilist.RemoveAt(0);
}
else
{
   // what were you planning to do if you were given a read only list anyway?
}

누군가 당신에게 Array 또는 List를 전달하면 매번 플래그를 확인하고 폴 백이 있으면 코드가 정상적으로 작동합니다 …하지만 실제로; 누가합니까? 분석법에 추가 구성원이 필요할 수있는 목록이 필요한 경우 미리 알 수 없습니다. 메소드 서명에서 지정하지 않습니까? 다음과 같은 읽기 전용 목록을 통과 한 경우 정확히 무엇을 int[]하시겠습니까?

/를 올바르게List<T> 사용 하는 코드로 대체 할 수 있습니다 . 당신은 할 수 없습니다 당신이 대체 할 수 있음을 보증 / 코드로 사용 .IList<T>ICollection<T> IList<T>ICollection<T>List<T>

구체적인 유형 대신 추상화를 사용한다는 주장에 대해서는 단일 책임 원칙 / 인터페이스 분리 원칙에 대한 호소력이 있습니다. 가능한 가장 좁은 인터페이스에 따라 다릅니다. 대부분의 경우 a를 List<T>사용하는 경우 더 좁은 인터페이스를 대신 사용할 수 있다고 생각하는 이유는 IEnumerable<T>무엇입니까? 항목을 추가 할 필요가없는 경우 종종 더 적합합니다. 컬렉션에 추가해야하는 경우 콘크리트 유형을 사용하십시오 List<T>.

나에게 IList<T>(그리고 ICollection<T>)는 .NET 프레임 워크의 최악의 부분입니다. IsReadOnly최저 놀람의 원칙을 위반합니다. Array항목을 추가, 삽입 또는 제거 할 수없는 클래스와 같은 클래스 는 Add, Insert 및 Remove 메서드를 사용하여 인터페이스를 구현해서는 안됩니다. (또한 /software/306105/implementing-an-interface-when-you-dont-need-one-of-the-properties 참조 )

IList<T>조직에 잘 맞는가? 동료가 IList<T>대신에 사용할 메소드 서명을 변경 List<T>하도록 요청하는 경우,에 요소를 추가하는 방법을 물어보십시오 IList<T>. 그들이 알지 못하는 경우 IsReadOnly(그리고 대부분의 사람들은 모르는 경우)를 사용하지 마십시오 IList<T>. 이제까지.


IsReadOnly 플래그는 ICollection <T>에서 가져오고 컬렉션에서 항목을 추가 또는 제거 할 수 있는지 여부를 나타냅니다. 그러나 실제로 혼란스럽게하기 위해 대체 할 수 있는지 여부는 나타내지 않으며 배열의 경우 IsReadOnlys == true를 반환 할 수 있습니다.

IsReadOnly에 대한 자세한 내용 은 ICollection <T>의 msdn 정의를 참조하십시오.


답변

List<T>의 특정 구현으로 IList<T>, T[]정수 색인을 사용하여 선형 배열과 같은 방식으로 처리 할 수있는 컨테이너입니다 . IList<T>메소드의 인수 유형으로 지정할 때 컨테이너의 특정 기능이 필요하다는 것만 지정합니다.

예를 들어, 인터페이스 사양에서는 특정 데이터 구조를 사용하지 않습니다. List<T>요소를 선형 배열로 액세스, 삭제 및 추가 할 때와 동일한 성능 이 구현 됩니다. 그러나 링크 된 목록으로 뒷받침되는 구현을 상상할 수 있습니다. 단, 끝에 요소를 추가하는 것이 더 저렴하지만 (일정 시간) 랜덤 액세스는 훨씬 더 비쌉니다. .NET LinkedList<T>은 구현 하지 않습니다IList<T> .

이 예는 또한 인수 목록에서 인터페이스가 아닌 구현을 지정해야하는 상황이있을 수 있음을 알려줍니다.이 예에서는 특정 액세스 성능 특성이 필요할 때마다. 이것은 일반적으로 컨테이너의 특정 구현에 대해 보장됩니다 ( List<T>문서 : ” IList<T>필요에 따라 크기가 동적으로 증가하는 배열을 사용하여 일반 인터페이스를 구현합니다 “).

또한 필요한 최소한의 기능을 노출하는 것이 좋습니다. 예를 들어. 목록의 내용을 변경할 필요가 없으면 확장을 사용 IEnumerable<T>하는 것이 IList<T>좋습니다.


답변

구체적인 구현보다 인터페이스를 사용해야하는 이유를 정당화하는 대신 질문을 조금 돌리고 인터페이스 대신 구체적인 구현을 사용해야하는 이유를 정당화하려고합니다. 정당화 할 수 없으면 인터페이스를 사용하십시오.


답변

IList <T>는 인터페이스이므로 다른 클래스를 상속하고 IList <T>를 구현하면서 List <T>를 상속하면 그렇게 할 수 없습니다.

예를 들어 클래스 A가 있고 클래스 B가 상속하면 List <T>를 사용할 수 없습니다.

class A : B, IList<T> { ... }