문제

할 수 있는 사람에게 설명을 왜 사용하려는 것이 명령을 통해 목록에서 C#?

관련 질문: 그것이 왜 나쁜 것으로 간주를 노출 List<T>

도움이 되었습니까?

해결책

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

내부적으로 사용하는 경우별로 신경 쓰지 않고 List<T> 괜찮을 수도 있습니다.

다른 팁

덜 대중적인 대답은 프로그래머가 소프트웨어가 전 세계를 재사용하는 척하는 것을 좋아하는 것입니다. 당신 자신.

건축 우주 비행사. 이미 .NET 프레임 워크에있는 것들에 무엇이든 추가 할 수있는 자신만의 ilist를 쓸 가능성은 너무 멀어서 "모범 사례"를 위해 예약 된 이론적 젤리 토트입니다.

Software astronauts

분명히 당신이 인터뷰에서 어떤 사용을 사용하는지, 당신은 Ilist, Smile, 그리고 둘 다 너무 영리한 것에 대해 자신을 기쁘게 생각합니다. 또는 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);
}

유용한 동료 "Refactors"수락 방법 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를 사용했다는 것입니다.u003CT> /icollectionu003CT> 잘못된. iCollection을 사용하는 경우u003CT> 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?
}

누군가가 당신에게 배열이나 목록을 통과하면 매번 깃발을 확인하고 폴백이 있으면 코드가 잘 작동합니다. 그러나 실제로; 누가 그렇게합니까? 방법에 추가 회원을 데려 갈 수있는 목록이 필요한지 미리 알 수 없습니다. 메소드 서명에 그것을 지정하지 않습니까? 당신이 읽기 전용 목록을 통과했다면 정확히 무엇을 할 것인가 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, 항목을 추가, 삽입 또는 제거 할 수없는 것은 메소드를 추가, 삽입 및 제거하여 인터페이스를 구현해서는 안됩니다. (또한보십시오 https://softwareengineering.stackexchange.com/questions/306105/implementing-an-interface-when-you-dont-need-one-of-properties)

~이다 IList<T> 조직에 적합합니까? 동료가 사용할 메소드 서명을 변경하도록 요청하는 경우 IList<T> 대신에 List<T>, 그들이 어떻게 요소를 추가 할 것인지 물어보십시오. IList<T>. 그들이 모르는 경우 IsReadOnly (그리고 대부분의 사람들은 사용하지 않습니다. IList<T>. 항상.


IsReadonly 플래그는 ICollection에서 나옵니다u003CT> , 컬렉션에서 항목을 추가하거나 제거 할 수 있는지 여부를 나타냅니다. 그러나 실제로 사물을 혼동하기 위해서는 교체 할 수 있는지 여부를 나타내지 않습니다.

IsReadonly에 대한 자세한 내용은 참조하십시오 iCollection의 MSDN 정의u003CT> .ISREADONLY

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

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

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

또한 필요한 기능이 가장 적은 기능을 노출시키는 것을 고려할 수 있습니다. 예를 들어. 목록의 내용을 변경할 필요가 없다면 아마도 사용을 고려해야합니다. IEnumerable<T>, 어느 IList<T> 확장.

콘크리트 구현을 통해 인터페이스를 사용해야하는 이유를 정당화하는 대신 질문을 조금 돌립니다. 인터페이스 대신 콘크리트 구현을 사용하는 이유를 정당화하십시오. 정당화 할 수 없다면 인터페이스를 사용하십시오.

일리스트u003CT> 인터페이스이므로 다른 클래스를 상속하고 여전히 ILIST를 구현할 수 있습니다.u003CT> 상속 목록u003CT> 그렇게하지 못하게합니다.

예를 들어 클래스 A가 있고 클래스 B가 상속되면 목록을 사용할 수 없습니다.u003CT>

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

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

이 특정한 경우에는 본질적으로 언어 구조에 대해 이야기하고 있기 때문에 일반적으로 언어 구조물이 아니라 일반적으로 중요하지 않지만 예를 들어 목록이 필요한 것을 지원하지 않았다고 말합니다. 나머지 앱에서 ILIST를 사용한 경우 자신의 사용자 정의 클래스로 목록을 확장 할 수 있으며 리팩토링 없이도 여전히 통과 할 수 있습니다.

이를위한 비용은 최소화됩니다. 나중에 두통을 저장하지 않겠습니까? 인터페이스 원칙이 전부입니다.

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

이 경우 Ilist를 구현하는 모든 수업에서 통과 할 수 있습니다.u003CBar> 상호 작용. 목록을 사용한 경우u003CBar> 대신 목록 만u003CBar> 인스턴스를 전달할 수 있습니다.

Ilistu003CBar> 길은 목록보다 느슨하게 결합됩니다u003CBar> 방법.

구현을 통해 인터페이스를 사용하는 가장 중요한 경우는 API 매개 변수입니다. API가 목록 매개 변수를 사용하는 경우 사용하는 사람은 누구나 목록을 사용해야합니다. 매개 변수 유형이 Ilist 인 경우 발신자는 훨씬 더 자유롭고 들어 본 적이없는 클래스를 사용할 수 있습니다. 코드가 작성되었을 때도 존재하지 않았을 수도 있습니다.

이 목록 중 어느 것도 ILIST 질문 (또는 답변)이 서명 차이를 언급하지 않는다는 것을 뛰어 넘습니다. (이것이 제가이 질문을 검색 한 이유입니다!)

따라서 ILIST에서 찾을 수없는 목록에 포함 된 방법은 다음과 같습니다. 적어도 .NET 4.5 (2015 년경).

  • addrange
  • AsReadonly
  • 바이너리 검색
  • 용량
  • Conversall
  • 존재합니다
  • 찾다
  • findall
  • findindex
  • Findlast
  • FindlastIndex
  • 각각
  • getRange
  • insertrange
  • lastindexof
  • 모두 제거
  • 리무지
  • 뒤집다
  • 종류
  • toarray
  • trimexcess
  • 참으로

.NET 5.0이 대체되면 어떻게해야합니까? System.Collections.Generic.List<T> 에게 System.Collection.Generics.LinearList<T>. .NET은 항상 이름을 소유합니다 List<T> 그러나 그들은 그것을 보장합니다 IList<T> 계약입니다. 따라서 IMHO (Atleast I)는 누군가의 이름을 사용하지 않아야합니다 (이 경우 .NET이지만) 나중에 문제가 발생합니다.

사용하는 경우 IList<T>, 발신자는 항상 일할 수있는 일이며, 구현자는 기본 컬렉션을 대체 콘크리트 구현으로 자유롭게 변경할 수 있습니다. IList

모든 개념은 기본적으로 위의 대부분의 답변에서 구체적인 구현을 통해 인터페이스를 사용하는 이유와 관련하여 언급됩니다.

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

IList<T> MSDN 링크

  1. 추가하다
  2. 분명한
  3. 포함
  4. 에게 복사
  5. getEnumerator
  6. 인덱스
  7. 끼워 넣다
  8. 제거하다
  9. 제거

List<T> 이 9 가지 방법 (확장 방법은 포함되지 않음)을 구현하는데, 그 위에 약 41 개의 공개 방법이 있으며,이 방법은 응용 프로그램에서 사용할 수있는 것을 고려해야합니다.

List<T> MSDN 링크

당신은 것이기 때문에 정의하는 명령 또는 ICollection 열까지 다른 구현이의 인터페이스가 있습니다.

할 수 있는 IOrderRepository 을 정의하는 주문 컬렉션 중 하나에서 명령 또는 ICollection.할 수 있습니다 다른 종류의 구현을 제공하는 목록의 순서로 그들을 준수하"규칙"에 의해 정의된 명령 또는 ICollection.

인터페이스는 최소한 기대하는 방법을 얻을 수 있도록합니다.; 인터페이스의 정의를 알고 있습니다. 인터페이스를 상속하는 클래스에 의해 구현 될 모든 추상 방법. 따라서 어떤 사람이 일부 추가 기능을 위해 인터페이스에서 상속받은 방법 외에 몇 가지 방법으로 자신의 클래스를 만들면 서브 클래스에 대한 참조를 사용하는 것이 좋습니다 (이 경우에는 인터페이스) 및 콘크리트 클래스 객체를 할당하십시오.

추가적인 장점은 콘크리트 클래스의 방법 중 적은 소수만에 구독 할 때 코드가 콘크리트 클래스의 변경으로부터 안전하며 콘크리트 클래스가 인터페이스에서 상속되는 한있을 때까지있을 것입니다. 사용. 따라서 콘크리트 클래스에 더 많은 기능을 변경하거나 추가하기 위해 구체적인 구현을 작성하는 코더에게 귀하를위한 안전과 자유.

ilist <>은 다른 포스터의 조언에 따라 거의 항상 바람직하지만 참고 .NET 3.5 SP 1에는 버그가 있습니다 WCF DatacontractSerializer를 사용하여 하나 이상의 직렬화 / 사제 화를 통해 ILIST <>을 실행할 때.

이제이 버그를 해결하기위한 SP가 있습니다. KB 971030

구현이 아닌 인터페이스에 대해 프로그래밍하라는 순수한 OO 접근법 중 하나를 포함하여 여러 각도 에서이 인수를 볼 수 있습니다. 이 생각으로 Ilist를 사용하면 처음부터 정의하는 인터페이스를 통과하고 사용하는 것과 같은 원칙을 따릅니다. 또한 인터페이스가 일반적으로 제공하는 확장 성 및 유연성 요소를 믿습니다. 클래스가 ilist를 묵시하는 경우u003CT> 확장되거나 변경되어야합니다. 소비 코드가 변경 될 필요가 없습니다. ILIST 인터페이스 계약이 무엇을 준수하는지 알고 있습니다. 그러나 구체적인 구현 및 목록을 사용합니다u003CT> 변경되는 클래스에서 호출 코드도 변경해야 할 수도 있습니다. 이것은 Ilist를 준수하는 클래스 때문입니다u003CT> 목록을 사용하여 구체적인 유형으로 보장되지 않는 특정 행동을 보장합니다.u003CT> .

또한 목록의 기본 구현을 수정하는 것과 같은 작업을 수행 할 수있는 힘이 있습니다.u003CT> ILIST를 구현하는 수업에서u003CT> .add, .remove 또는 기타 Ilist 메소드는 개발자에게 많은 유연성과 힘, 그렇지 않으면 목록에 의해 사전 정의됩니다u003CT>

일반적으로, 좋은 접근법은 대중이 직면 한 API에 ILIST를 사용하고 (적절한 경우, 의미론이 필요하다면) 내부적으로 나열되어 API를 구현하는 것입니다. 이를 통해 클래스를 사용하는 코드를 깨지 않고 ILIST의 다른 구현으로 변경할 수 있습니다.

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

API가 Foreach Loops 등에 만 사용되는 경우 대신 ienumerable을 노출시키는 것을 고려할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top