Programing

명부

lottogame 2020. 2. 14. 22:27
반응형

명부 또는 IList


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

관련 질문 : 노출이 나쁜 이유는 무엇입니까?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 메서드를 사용하여 인터페이스를 구현해서는 안됩니다. (또한 https://softwareengineering.stackexchange.com/questions/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>는 인터페이스이므로 다른 클래스를 상속하고 여전히 List <T>를 상속하면서 IList <T>를 구현할 수 있습니다.

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

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

TDD 및 OOP의 원칙은 일반적으로 구현이 아닌 인터페이스로 프로그래밍하는 것입니다.

이 특정 경우에는 본질적으로 사용자 정의 언어가 아닌 언어 구조에 대해 이야기하기 때문에 List가 필요한 것을 지원하지 않는다고 말한 경우와 같이 말하십시오. 나머지 앱에서 IList를 사용한 경우 자체 사용자 정의 클래스로 List를 확장하고 리팩토링하지 않고 계속 전달할 수 있습니다.

이 작업을 수행하는 데 드는 비용이 최소화됩니다. 나중에 두통을 피하십시오. 인터페이스 원리가 중요합니다.


public void Foo(IList<Bar> list)
{
     // Do Something with the list here.
}

이 경우 IList <Bar> 인터페이스를 구현하는 모든 클래스를 전달할 수 있습니다. List <Bar>를 대신 사용하면 List <Bar> 인스턴스 만 전달할 수 있습니다.

IList <Bar> 방식은 List <Bar> 방식보다 느슨하게 결합되어 있습니다.


구현보다 인터페이스를 사용하는 가장 중요한 경우는 API의 매개 변수에 있습니다. API가 List 매개 변수를 사용하는 경우 API를 사용하는 사람은 누구나 List를 사용해야합니다. 매개 변수 유형이 IList 인 경우 호출자는 훨씬 더 많은 자유를 얻게되며, 들어 본 적이없는 클래스를 사용할 수 있습니다.이 클래스는 코드를 작성할 때 존재하지 않았을 수도 있습니다.


이러한 List 대 IList 질문 (또는 답변) 중 어느 것도 서명 차이를 언급하지 않는다고 놀랍습니다. (왜 내가이 질문을 검색 했습니까!)

적어도 .NET 4.5 (2015 년경)부터 IList에는없는 List에 포함 된 메소드가 있습니다.

  • AddRange
  • AsReadOnly
  • 이진 검색
  • 생산 능력
  • 모두 변환
  • 존재
  • 찾기
  • 모두 찾기
  • 찾기 색인
  • 마지막 찾기
  • 마지막 색인 찾기
  • 각각
  • GetRange
  • InsertRange
  • LastIndexOf
  • 모두 제거
  • 범위 제거
  • 종류
  • ToArray
  • 트림 과잉
  • TrueForAll

무엇 .NET의 경우 5.0을 대체 System.Collections.Generic.List<T>하는 System.Collection.Generics.LinearList<T>. .NET은 항상 이름을 소유 List<T>하지만 IList<T>계약 임을 보증합니다 . 따라서 IMHO 우리 (이스트 I)는 누군가의 이름을 사용하지 않아야하며 (이 경우 .NET이지만) 나중에 문제가 발생합니다.

을 사용하는 경우 IList<T>호출자는 항상 작동하도록 보장되며 구현자는 기본 컬렉션을 다른 대체 구현으로 자유롭게 변경할 수 있습니다.IList


모든 개념은 기본적으로 구체적인 구현보다 인터페이스를 사용하는 이유와 관련하여 위의 대부분의 답변에 명시되어 있습니다.

IList<T> defines those methods (not including extension methods)

IList<T> MSDN 링크

  1. 더하다
  2. 명확한
  3. 포함
  4. 에게 복사
  5. GetEnumerator
  6. IndexOf
  7. 끼워 넣다
  8. 없애다
  9. 제거

List<T> 응용 프로그램에서 사용할 방법을 고려하여 무게가 약 41 개의 공개 메소드가있는 것 외에도 9 가지 메소드 (확장 메소드 제외)를 구현합니다.

List<T> MSDN 링크


IList 또는 ICollection을 정의하면 인터페이스의 다른 구현을 위해 열릴 수 있기 때문입니다.

IList 또는 ICollection에서 주문 콜렉션을 정의하는 IOrderRepository를 원할 수 있습니다. 그런 다음 IList 또는 ICollection에 의해 정의 된 "규칙"을 따르는 한 주문 목록을 제공하기 위해 다양한 종류의 구현을 가질 수 있습니다.


인터페이스는 최소한 예상 한 메소드를 얻도록합니다 . 인터페이스의 정의를 인식하는 것, 즉 인터페이스를 상속하는 모든 클래스에 의해 구현되는 모든 추상 메소드. 따라서 어떤 사람이 인터페이스에서 추가 기능을 위해 상속받은 것 외에도 여러 가지 방법으로 자신의 거대한 클래스를 만들고, 당신에게 유용하지 않은 경우, 서브 클래스에 대한 참조를 사용하는 것이 좋습니다 (이 경우 구체적인 클래스 객체를 할당하십시오.

추가 장점은 콘크리트 클래스의 몇 가지 메소드 만 구독하므로 코드가 콘크리트 클래스의 변경으로부터 안전하고 콘크리트 클래스가 인터페이스에서 상속하는 한 거기에있는 메소드입니다 사용. 따라서 구체적인 구현을 작성하는 코더에게 자신의 안전을 보장하고 자신의 구체적인 클래스에 더 많은 기능을 추가하거나 추가 할 수 있습니다.


IList <>는 다른 포스터의 조언에 따라 거의 항상 바람직하지만 WCF DataContractSerializer를 사용하여 직렬화 / 역 직렬화를 두 번 이상 반복하여 IList <>를 실행할 때 .NET 3.5 sp 1에 버그가 있습니다.

이 버그를 수정하는 SP가 있습니다 : KB 971030


구현이 아닌 인터페이스에 대해 프로그래밍하는 순수한 OO 접근법 중 하나를 포함하여 여러 각도 에서이 주장을 볼 수 있습니다. 이러한 생각으로, IList 사용은 처음부터 정의한 인터페이스를 전달하고 사용하는 것과 동일한 원칙을 따릅니다. 또한 인터페이스가 일반적으로 제공하는 확장 성과 유연성 요소를 믿습니다. IList <T>를 구현하는 클래스를 확장하거나 변경해야하는 경우 소비 코드를 변경할 필요가 없습니다. IList Interface 계약이 준수하는 내용을 알고 있습니다. 그러나 변경되는 클래스에서 구체적인 구현과 List <T>를 사용하면 호출 코드도 변경해야 할 수 있습니다. IList <T>를 준수하는 클래스는 List <T>를 사용하는 구체적 유형에 의해 보장되지 않는 특정 동작을 보장하기 때문입니다.

또한 .Add, .Remove 또는 다른 IList 메서드를 구현하기 위해 클래스 IList <T>를 구현하는 클래스에서 List <T>의 기본 구현을 수정하는 것과 같은 작업을 수행 할 수있는 능력이 있으면 개발자에게 많은 유연성과 힘이 부여됩니다. 목록으로 <T>


일반적으로 적절한 방법은 공개 API에서 IList를 사용하고 (적절한 경우 목록 의미가 필요한 경우) API를 구현하기 위해 내부적으로 나열하는 것입니다. 이를 통해 클래스를 사용하는 코드를 중단하지 않고 다른 IList 구현으로 변경할 수 있습니다.

클래스 이름 목록은 다음 .net 프레임 워크에서 변경 될 수 있지만 인터페이스가 계약되어 있으므로 인터페이스가 변경되지 않습니다.

API가 foreach 루프 등에서 만 사용되는 경우 대신 IEnumerable을 노출하는 것이 좋습니다.

참고 URL : https://stackoverflow.com/questions/400135/listt-or-ilistt



반응형