ProgramingTip

IList를 반환하고 있습니다.

bestdevel 2020. 10. 7. 07:56
반응형

IList를 반환하고 있습니다. T [] 또는 List를 반환하는 것보다 나쁨?


다음과 같은 질문에 대한 대답 : List <T> 또는 IList <T>는 항상 인터페이스를 반환하는 것이 컬렉션의 구체적인 구현을 반환하는 것보다 낫다는 데 동의하는 것입니다. 그러나 나는 이것으로 어려움을 겪고 있습니다. 인터페이스 인스턴스화는 불가능한 메서드가 인터페이스를 반환하는 경우 실제로 구현을 반환합니다. 두 가지 작은 방법을 작성하여 약간 실험했습니다.

public static IList<int> ExposeArrayIList()
{
    return new[] { 1, 2, 3 };
}

public static IList<int> ExposeListIList()
{
    return new List<int> { 1, 2, 3 };
}

그리고 내 테스트 프로그램에서 사용하십시오.

static void Main(string[] args)
{
    IList<int> arrayIList = ExposeArrayIList();
    IList<int> listIList = ExposeListIList();

    //Will give a runtime error
    arrayIList.Add(10);
    //Runs perfectly
    listIList.Add(10);
}

두 경우 모두 새 값을 추가 할 때 컴파일러에서 오류가 발생하지 않지만 배열을로 노출하는 방법은 IList<T>뭔가를 추가하려고 할 때 실행 오류를 발생 시켰습니다. 내 방법에서 따라서 무슨 일이 일어나고 있는지 모르는 사람들은 오류 위험없이 값을 추가 할 수 있도록 먼저 내 IListList복사해야 우리 합니다. 그들은과 그들이 물론 경우있는 거 거래 볼 수있는 유형 체킹을 수행 할 수 있습니다 List또는를 Array하지만 그렇게하지 않으면, 컬렉션에 항목 그들은을 추가 할 그들이 다른 선택의 여지가 복사되지해야 우리 IListList하더라도, 이미List . 배열은 절대로 노출되지 않는 IList소개?

나의 또 다른 관심사는 질문 (강조 내) 에 대한 수용된 답변에 기반합니다 .

다른 사람들이 사용할 수있는 라이브러리를 통해 클래스를 노출하는 경우 일반적으로 구체적인 구현이 인터페이스를 통해 클래스 를 노출합니다. 나중에 다른 구체적인 클래스를 사용하기 위해 클래스 구현을 변경하기로 결정한 경우 도움이됩니다. 이 경우 인터페이스가 변경되지 않은 라이브러리가 없습니다.

내부적으로 만 사용하는 경우 신경 쓰지 않을 수 있습니다.

누군가가 실제로 값을 추가 / 제거하기 위해 IList<T>ExposeListIlist()방법 에서 얻은 내 방법을 사용하여 상상해 발견 . 모든 것이 잘 작동합니다. 그러나 이제는 대답에서 알 수없는 인터페이스를 반환하는 것이 더 유연하기 때문에 목록 대신 배열을 반환합니다. 그러면 치료를 받고 있습니다 ...

TLDR :

1) 인터페이스를 노출하면 불필요한 캐스트가 발생합니까? 상관 없어?

2) 라이브러리 사용자가 캐스트를 사용하지 않는 방법이 완벽하게 유지 되더라도 방법을 변경하면 코드가 깨질 수 있습니다.

나는 아마도 그것을 반환하는 것이 구현을 반환 할 것입니다.


이것이 귀하의 질문에 직접적으로 대답하는 것은 어떤 방식이든 .NET 4.5 이상에서는 공개 또는 보호 된 API를 설계 할 때 다음 규칙을 따르는 것이 좋습니다.

  • IEnumerable<T>열거 형 만 사용할 수있는 경우 반환을 수행 합니다.
  • IReadOnlyCollection<T>및 항목 수 열거를 모두 사용할 수 있으면 반환 하십시오.
  • IReadOnlyList<T>열거, 항목 수 및 인덱싱 된 액세스를 사용할 수있는 경우 반환을 수행 합니다.
  • ICollection<T>열거 항목, 반환 수 및 수정이 가능 합니다.
  • IList<T>열거, 항목 수, 인덱싱 된 액세스 및 수정을 사용할 수있는 경우 반환 합니다.

마지막 두 옵션은 해당 메소드 IList<T>구현으로 배열을 반환합니다 .


아니요, 소비자는 IList정확히 무엇인지 이해하기 때문 입니다.

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

당신은 확인할 수 IList.IsFixedSizeIList.IsReadOnly당신이 그것으로 원하는 일을.

나는 IList팻 인터페이스의 예 라고 생각 하고 여러 개의 작은 인터페이스로 분할되어야 하며 배열을 .NET으로 반환 할 때 Liskov 대체 원칙을 위반 합니다 IList.

인터페이스 반환에 대한 결정을 내리고 페이지에서 더 읽어보세요.


최신 정보

더 파고 나는 그 발견 IList<T>구현하지 않습니다 IListIsReadOnly기본 인터페이스를 통해 액세스 할 수 ICollection<T>있지만 거기 IsFixedSize에 대해 IList<T>. 제네릭 IList <>가 비 제네릭 IList를 상속하지 않는 이유 에 대해 자세히 알아보십시오 .


모든 "인터페이스 대 구현"질문과 마찬가지로 공용 멤버를 노출하는 것이 의미하는 바를 이해해야합니다.이 클래스의 공용 API를 정의합니다.

당신이 노출되면 List<T>멤버 (필드, 재산, 방법, ...)로, 해당 회원의 소비자에게이 방법을 액세스하여 얻은 유형 입니다List<T> 그의 유래, 또는 뭔가.

이제 인터페이스를 노출하면 구체적인 유형을 사용하여 클래스의 "구현 세부 정보"를 숨 깁니다. 물론 당신은 인스턴스화 할 수 없습니다 IList<T>,하지만 당신은을 사용할 수 있습니다 Collection<T>, List<T>, 유도 또는 그 자신의 유형 구현 IList<T>.

실제 질문은 "왜 않습니다 Array구현 IList<T>" , 또는 "왜는이 IList<T>많은 회원 그래서 인터페이스를" .

또한 해당 구성원의 소비자가 원하는 작업에 따라 다릅니다. 실제로 회원을 통해 내부 회원을 반환하는 경우 Expose...에는 new List<T>(internalMember)어쨌든를 반환하고 싶을 것 입니다. 그렇지 않으면 소비자가이를 IList<T>통해 내부 회원을 캐스트 하고 수정할 수 있기 때문입니다.

소비자가 결과를 반복하기를 기대하는 경우 IEnumerable<T>또는 IReadOnlyCollection<T>대신 노출하십시오 .


문맥에서 벗어난 담요 따옴표에주의하십시오.

인터페이스를 반환하는 것이 구체적인 구현을 반환하는 것보다 낫습니다.

이 인용문은 SOLID 원칙 의 맥락에서 사용되는 경우에만 의미가 있습니다 . 5 가지 원칙이 있지만이 논의의 목적을 위해 마지막 3 가지에 대해서만 이야기하겠습니다.

종속성 반전 원리

하나는“추상화에 의존해야합니다. 결심에 의존하지 마십시오.”

제 생각에는이 원칙이 가장 이해하기 어렵습니다. 그러나 견적을주의 깊게 살펴보면 원래 견적과 매우 유사합니다.

인터페이스 (추상화)에 따라 다릅니다. 구체적인 구현 (콘크리트)에 의존하지 마십시오.

이것은 여전히 ​​약간 혼란 스럽지만 다른 원칙을 함께 적용하기 시작하면 훨씬 더 이해하기 시작합니다.

Liskov 대체 원리

"프로그램의 객체는 해당 프로그램의 정확성을 변경하지 않고 하위 유형의 인스턴스로 대체 할 수 있어야합니다."

지적했듯이을 반환하는 Array것은 List<T>둘 다 구현하더라도 a를 반환하는 것과 분명히 다른 동작 IList<T>입니다. 이것은 확실히 LSP의 위반입니다.

깨달아야 할 중요한 것은 인터페이스가 소비자 에 관한 것이라는 것 입니다. 인터페이스를 반환하는 경우 프로그램의 동작을 변경하지 않고 해당 인터페이스의 모든 메서드 또는 속성을 사용할 수 있다는 계약을 만든 것입니다.

인터페이스 분리 원칙

"많은 클라이언트 별 인터페이스가 하나의 범용 인터페이스보다 낫습니다."

인터페이스를 반환하는 경우 구현에서 지원하는 가장 클라이언트 별 인터페이스를 반환해야합니다. 즉, 클라이언트가 Add메서드 를 호출 할 것으로 기대하지 않는 경우 메서드가있는 인터페이스를 반환해서는 안됩니다 Add.

안타깝게도 .NET 프레임 워크 (특히 초기 버전)의 인터페이스가 항상 이상적인 클라이언트 특정 인터페이스는 아닙니다. @Dennis가 그의 답변에서 지적했듯이 .NET 4.5 이상에는 더 많은 선택 사항이 있습니다.


인터페이스를 반환하는 것이 컬렉션의 구체적인 구현을 반환하는 것보다 반드시 낫지는 않습니다. 구체적인 유형 대신 인터페이스를 사용해야하는 좋은 이유가 항상 있어야합니다. 귀하의 예에서는 그렇게하는 것이 무의미한 것 같습니다.

인터페이스를 사용하는 유효한 이유는 다음과 같습니다.

  1. 인터페이스를 반환하는 메서드의 구현이 어떻게 생겼는지 알 수 없으며 시간이 지남에 따라 개발 될 수 있습니다. 다른 회사에서 작성한 다른 사람 일 수 있습니다. 따라서 필요한 사항에 동의하고 기능을 구현하는 방법은 그들에게 맡기면됩니다.

  2. 유형이 안전한 방식으로 클래스 계층 구조와 독립적 인 몇 가지 공통 기능을 노출하려고합니다. 동일한 메서드를 제공해야하는 다른 기본 유형의 개체는 인터페이스를 구현합니다.

1과 2는 기본적으로 같은 이유라고 주장 할 수 있습니다. 궁극적으로 동일한 요구로 이어지는 두 가지 시나리오입니다.

"계약입니다". 계약이 본인과 있고 애플리케이션이 기능과 시간 모두에서 종료 된 경우 인터페이스를 사용할 필요가없는 경우가 많습니다.

참고 URL : https://stackoverflow.com/questions/34334363/is-returning-ilistt-worse-than-returning-t-or-listt

반응형