왜 배열이 IList를 구현합니까?


141

System.Array 클래스 의 정의를 참조하십시오

public abstract class Array : IList, ...

이론적으로, 나는이 비트를 쓸 수 있고 행복해야한다

int[] list = new int[] {};
IList iList = (IList)list;

또한 iList에서 모든 메소드를 호출 할 수 있어야합니다

 ilist.Add(1); //exception here

내 질문은 왜 예외가 아닌 Array가 IList를 구현 하는 이유 입니까?


22
좋은 질문입니다. 나는 뚱뚱한 인터페이스 (이런 종류의 디자인에 대한 기술적 용어)라는 아이디어를 좋아하지 않았습니다.
Konrad Rudolph


2
실제로 LSP에 관심이있는 사람이 있습니까? 그것은 나에게 매우 학문적 인 것 같습니다.
Gabe

13
@Gabe, 더 큰 코드베이스로 작업해야합니다. 동작을 구현하고 (인터페이스에서 상속) 지원하지 않거나 지원하지 않는 것을 무시하면 냄새, 난독 화, 캐스팅 및 마지막으로 버그가있는 코드가 발생합니다.
Marius

3
@Gabe 포함 된 엔티티가 아닌 변경 가능성을 의미하는 컬렉션입니다. IRWList <> 및 IReadList <>를 모두 구현하는 형식의 클래스 멤버를 만들 수 있으며 클래스에서 내부적으로 if IRWList <>를 사용하여 IReadList로 노출 할 수 있습니다. 예, 복잡성을 어딘가에 두어야하지만, 이것이 LSP를 매우 훌륭한 설계 원칙으로 무시하는 데 어떻게 적용되는지는 알지 못합니다 (IsReadOnly 속성에 대해 몰랐지만 IList가 소비자 입장에서 더 복잡해집니다)
Marius

답변:


94

배열은 인덱스에 의한 빠른 액세스를 허용하고 IList/ IList<T>는 이것을 지원하는 유일한 컬렉션 인터페이스입니다. 아마도 당신의 진짜 질문은 "인덱서가있는 상수 컬렉션을위한 인터페이스가없는 이유"입니다. 그리고 나는 대답이 없습니다.

컬렉션에 대한 읽기 전용 인터페이스도 없습니다. 그리고 인덱서 인터페이스로 일정한 크기 이상의 것을 놓치고 있습니다.

IMO 컬렉션의 기능에 따라 더 많은 (일반적인) 컬렉션 인터페이스가 있어야합니다. List인덱서가있는 것은 정말 바보 같은 IMO이기 때문에 이름도 달라야했습니다 .

  • 그냥 열거 IEnumerable<T>
  • 읽기 전용이지만 인덱서 없음 (.Count, .Contains, ...)
  • 크기 조정 가능하지만 인덱서 없음 (예 : (Add, Remove, ...) current와 같이 설정) ICollection<T>
  • 인덱서 (인덱서, indexof, ...)를 사용하여 읽기 전용
  • 인덱서가있는 일정한 크기 (세터가있는 인덱서)
  • 인덱서 (Insert, ...) 전류의 가변 크기 IList<T>

현재 컬렉션 인터페이스가 나쁜 디자인이라고 생각합니다. 그러나 그들은 어떤 방법이 유효한지 알려주는 속성을 가지고 있기 때문에 (이 방법의 계약의 일부입니다) 대체 원칙을 위반하지 않습니다.


14
답변 해주셔서 감사합니다. 그러나 나는 오히려 질문을 그대로 둡니다. 이유는 간단합니다. 인터페이스는 공개 계약입니다. 구현하는 경우 모든 구성원을 완전히 구현해야합니다. 그렇지 않으면 LSP가 중단되고 일반적으로 나쁜 냄새가 나지 않습니까?
oleksii

16
LSP를 깨뜨립니다. 목록에없는 경우 콘크리트 유형에 관계없이 Add (item) 항목을 목록에 추가해야합니다. 예외적 인 경우를 제외하고. 배열 구현에서 예외가 아닌 경우에는 예외가 발생하는데, 그 자체로는 나쁜 습관입니다
Rune FS

2
@smelch 미안하지만 LSP가 잘못되었습니다. 배열은 구현되지 않으므로 add해당 기능이 필요할 때 수행하는 것으로 대체 할 수 없습니다.
룬 FS

7
나는 그것이 것을 인정 기술적으로 LSP를 위반하지 않기 때문 문서는 당신이 확인해야합니다 상태 IsFixedSizeIsReadOnly특성, 그것은 확실히 위반 말할를 수행 원칙 묻지최소 놀라운 원리 . 9 가지 방법 중 4 가지에 대해 예외를 던질 때 왜 인터페이스를 구현해야합니까?
Matthew

11
원래 질문 이후로 시간이 지났습니다. 그러나 .Net 4.5에는 추가 인터페이스 IReadOnlyListIReadOnlyCollection이 있습니다.
Tobias

43

는 섹션 발언 문서 에 대해 IList말한다

IList는 ICollection 인터페이스의 자손이며 모든 비 제네릭 목록의 기본 인터페이스입니다. IList 구현은 읽기 전용, 고정 크기 및 가변 크기의 세 가지 범주로 분류됩니다 . 읽기 전용 IList는 수정할 수 없습니다. 고정 크기 IList는 요소를 추가하거나 제거 할 수 없지만 기존 요소를 수정할 수는 있습니다. 가변 크기 IList를 사용하면 요소를 추가, 제거 및 수정할 수 있습니다.

분명히 배열은 고정 크기 범주에 속하므로 인터페이스의 정의에 따라 의미가 있습니다.


4
나는 그들이 많은 인터페이스로 끝났을 것이라고 생각합니다. IListFixedSize, IListReadOnly ...
매그너스

9
그것은 실제로 문서의 관점에서 좋은 대답입니다. 그러나 나에게는 오히려 해킹처럼 보입니다. 클래스가 모든 멤버를 구현하려면 인터페이스가 얇고 단순해야합니다.
oleksii

1
@oleksii : 동의합니다. 인터페이스와 런타임 예외는 가장 우아한 조합이 아닙니다. 이를 방어 Array하기 위해 Add메소드를 명시 적으로 구현하므로 우연히 호출 할 위험이 줄어 듭니다.
Brian Rasmussen

구현을 만들 때까지 IList수정 추가 / 제거를 모두 허용하지 않습니다 . 그러면 설명서가 더 이상 정확하지 않습니다. : P
Timo

1
@Magnus - 닷넷 4.5, 추가 인터페이스있다 IReadOnlyListIReadOnlyCollection이 .
RBT

17

때문에 모든 IList의는 변경할 수 있습니다 (참조 IList.IsFixedSize하고 IList.IsReadOnly), 및 배열 확실히 고정 된 크기의 목록처럼 동작합니다.

귀하의 질문이 실제로 " 비 제네릭 인터페이스를 구현하는 이유 "인 경우, 제네릭이 나오기 전에 이러한 문제가 발생했다는 것이 답입니다.


10
@oleksii : 아니요, 인터페이스 IList 자체 가 변경 불가능할 수 있다고 알려 주기 때문에 LSP를 중단하지 않습니다 . 실제로 변경 가능하다는 보장이 있고 배열에서 달리 지시 경우 규칙을 어기 게됩니다.
user541686

사실, 배열은 일반적인 경우 브레이크 LSP를 수행 IList<T>하고 제네릭이 아닌 경우에 휴식하지 않습니다 IList: enterprisecraftsmanship.com/2014/11/22/...
블라디미르

5

읽기 전용 컬렉션을 처리하는 방법과 Array가 읽기 전용인지 여부를 명확하게 알지 못했던 시대부터 우리가 가진 유산입니다. IList 인터페이스에는 IsFixedSize 및 IsReadOnly 플래그가 있습니다. IsReadOnly 플래그는 컬렉션을 전혀 변경할 수 없음을 의미하며 IsFixedSize는 컬렉션이 항목을 추가 또는 제거 할 수는 있지만 수정할 수는 없음을 의미합니다.

닷넷 4.5의 시점에서 그렇게 일부 "중간"인터페이스는 읽기 전용 컬렉션으로 작업에 필요하다는 것을 분명 IReadOnlyCollection<T>하고 IReadOnlyList<T>소개되었다.

다음은 세부 사항을 설명하는 훌륭한 블로그 게시물 입니다. .NET의 컬렉션 만 읽기


0

IList 인터페이스의 정의는 "인덱스로 개별적으로 액세스 할 수있는 비 제네릭 개체 모음을 나타냅니다." 배열은이 정의를 완전히 만족하므로 인터페이스를 구현해야합니다. Add () 메서드를 호출 할 때 "System.NotSupportedException : 컬렉션의 크기가 고정되어 있습니다."예외가 발생하며 배열의 용량을 동적으로 늘릴 수 없기 때문에 발생했습니다. 용량은 배열 객체를 생성하는 동안 정의됩니다.


0

배열을 IList (및 전 이적으로 ICollection)로 구현하면 Linnum2Objects 엔진이 단순화되었습니다. IEnumerable을 IList / ICollection으로 캐스팅하면 배열에서도 작동하기 때문입니다.

예를 들어 Count ()는 ICollection으로 캐스팅되고 배열의 구현은 Length를 반환하기 때문에 Array.Length를 덜 호출하게됩니다.

이것이 없으면 Linq2Objects 엔진은 배열에 대한 특수 처리를하지 않고 끔찍하게 수행하거나 배열에 대한 특수 처리를 추가하는 코드를 두 배로 늘려야합니다 (IList에서와 같이). 대신 배열이 IList를 구현하도록 선택해야합니다.

"왜"에 대한 나의 취향이다.


0

또한 구현 세부 정보 LINQ Last IList 검사, 목록을 구현하지 않으면 모든 Last 호출 속도를 늦추는 2 개의 검사가 필요하거나 O (N)을 취하는 배열에서 Last가 있어야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.