나는 IList가 인터페이스이고 List가 구체적인 유형이라는 것을 알고 있지만 여전히 각 유형을 언제 사용 해야할지 모르겠습니다. 내가 지금하고있는 일은 인터페이스를 사용하는 Sort 또는 FindAll 메서드가 필요하지 않은 것입니다. 내가 맞아? 인터페이스 또는 콘크리트 유형을 언제 사용할지 결정하는 더 좋은 방법이 있습니까?
나는 IList가 인터페이스이고 List가 구체적인 유형이라는 것을 알고 있지만 여전히 각 유형을 언제 사용 해야할지 모르겠습니다. 내가 지금하고있는 일은 인터페이스를 사용하는 Sort 또는 FindAll 메서드가 필요하지 않은 것입니다. 내가 맞아? 인터페이스 또는 콘크리트 유형을 언제 사용할지 결정하는 더 좋은 방법이 있습니까?
답변:
내가 따르는 두 가지 규칙이 있습니다.
따라서 컬렉션을 취하는 함수 나 메서드를 작성할 때는 List가 아니라 IList <T>, ICollection <T> 또는 IEnumerable <T>를 사용하도록 작성하십시오. System.Object도 T 일 수 있기 때문에 이종 목록에도 일반 인터페이스가 작동합니다. 이렇게하면 스택이나 다른 데이터 구조를 사용하기로 결정한 경우 골치 아프게됩니다. 함수에서해야 할 모든 것이 foreach이면 IEnumerable <T> 만 있으면됩니다.
반면, 함수에서 객체를 반환 할 때는 사용자가 캐스트하지 않고도 가장 풍부한 작업 집합을 사용자에게 제공하려고합니다. 이 경우 내부적으로 List <T>이면 복사본을 List <T>로 반환하십시오.
if...else와 체인을 사용하여 is계산할 수 있다는 것입니다 훨씬 더 풍부한 유형을 사용하여 캐스팅하고 어쨌든 사용합니다. 따라서 기본 인터페이스를 사용하여 가리지 않고 숨기는 것이 반드시 보장되는 것은 아닙니다 . 그러나 어렵게 만들면 소비 코드 작성자가 코드 사용 방식에 대해 두 번 생각하게 할 수 있습니다.
Add()과 유사 하고 Remove()컬렉션 이외의 효과를 가질 수 있다는 인상을 줄 수 있습니다. IEnumerable데이터 검색 방법을 사용하는 경우 와 같이 읽기 전용 인터페이스를 반환하는 경우가 많습니다. 소비자는 필요에 따라 더 풍부한 유형으로 투사 할 수 있습니다.
FxCop에서 확인한 Microsoft 지침은 공용 API에서 List <T> 사용을 권장하지 않습니다. IList <T>를 선호하십시오.
또한 이제는 거의 항상 1 차원 배열을 IList <T>로 선언하므로 Array.Length 대신 IList <T> .Count 속성을 일관되게 사용할 수 있습니다. 예를 들면 다음과 같습니다.
public interface IMyApi
{
IList<int> GetReadOnlyValues();
}
public class MyApiImplementation : IMyApi
{
public IList<int> GetReadOnlyValues()
{
List<int> myList = new List<int>();
... populate list
return myList.AsReadOnly();
}
}
public class MyMockApiImplementationForUnitTests : IMyApi
{
public IList<int> GetReadOnlyValues()
{
IList<int> testValues = new int[] { 1, 2, 3 };
return testValues;
}
}
사람들이 항상 간과하는 중요한 것이 있습니다.
일반 배열을 IList<T>매개 변수 를 허용하는 것으로 전달한 다음 호출 IList.Add()하여 런타임 예외를 수신 할 수 있습니다 .
Unhandled Exception: System.NotSupportedException: Collection was of a fixed size.
예를 들어 다음 코드를 고려하십시오.
private void test(IList<int> list)
{
list.Add(1);
}
다음과 같이 호출하면 런타임 예외가 발생합니다.
int[] array = new int[0];
test(array);
이는 일반 배열을 사용 IList<T>하여 Liskov 대체 원칙 을 위반 하기 때문에 발생합니다 .
이러한 이유로 전화 IList<T>.Add()를 거는 경우 List<T>대신을 (를) 요구하는 것이 좋습니다 IList<T>.
List<T>보다 선호하는 제안을 고려할 경우 권장 IList<T>이유를 알고 있어야 IList<T>합니다. (예를 들어 blogs.msdn.microsoft.com/kcwalina/2005/09/26/... )
IList<T>.Add(). 나는 당신 이 사용 해서는 안된다는 말이 아닙니다.IList<T> 단지 가능한 함정을 지적하고 있습니다. (내가 사용하는 경향이 IEnumerable<T>또는 IReadOnlyList<T>나 IReadOnlyCollection<T>에 우선 IList<T>내가 할 수있는 경우.)
나는 매개 변수를 취했지만 반환하지 않는 Lee의 조언에 동의합니다.
인터페이스를 반환하도록 메서드를 지정하면 소비하는 메서드를 모르더라도 나중에 정확한 구현을 자유롭게 변경할 수 있습니다. 나는 List <T>에서 변경할 필요가 없다고 생각했지만 나중에 추가 기능을 위해 사용자 지정 목록 라이브러리를 사용하도록 변경해야했습니다. IList <T> 만 반환했기 때문에 라이브러리를 사용하는 사람들은 코드를 변경하지 않아도됩니다.
물론 외부에서 볼 수있는 메소드 (공용 메소드)에만 적용하면됩니다. 나는 내부 코드에서도 개인적으로 인터페이스를 사용하지만 변경 사항을 변경하면 모든 코드를 직접 변경할 수 있으므로 반드시 필요한 것은 아닙니다.
IEnumerable
목적에 가장 적합한 유형을 사용하지 않아야합니다.
IEnumerable보다 구체적이지 않습니다 IList. 컬렉션의 항목을 반복 할 때
사용 IEnumerable합니다.
IList가
IList 구현 IEnumerable합니다. 컬렉션에 인덱스로 액세스하고 요소를 추가 및 삭제하는 등의 작업이 필요할 때
사용해야합니다 IList.
List구현 목록IList .
항상 가장 낮은 기본 유형을 사용하는 것이 가장 좋습니다. 이를 통해 인터페이스의 구현 자 또는 메소드의 소비자에게이면에서 원하는 것을 사용할 수있는 기회가 제공됩니다.
컬렉션의 경우 가능한 경우 IEnumerable을 사용하는 것이 좋습니다. 이것은 가장 융통성이 있지만 항상 적합하지는 않습니다.
ToList()반품 은 받지 말고 대신 IEnumerable<T>반품하십시오 IList<T>. 이제 고객은 노력없이 제공 할 수있는 혜택을 누릴 수 있습니다.
나는 이런 종류의 일에 대해 단단하고 빠른 규칙이 없다고 생각하지만, 절대적으로 필요할 때까지 가능한 가장 가벼운 방법을 사용하는 지침을 따릅니다.
예를 들어, Person수업과 수업 이 있다고 가정 해 봅시다 Group. Group여기에 목록이 나을 수 있도록 인스턴스는, 많은 사람들이있다. 에 목록 객체를 선언하면 Group을 사용 IList<Person>하고 인스턴스로 인스턴스화합니다 List.
public class Group {
private IList<Person> people;
public Group() {
this.people = new List<Person>();
}
}
그리고 모든 것을 필요로하지 않는다면 IList항상 사용할 수도 IEnumerable있습니다. 최신 컴파일러와 프로세서를 사용하면 속도 차이가 실제로 없다고 생각하므로 스타일의 문제입니다.
일반적으로 접하는 상황에서는 IList를 직접 사용하는 경우가 거의 없습니다.
보통 나는 그것을 메소드의 인수로 사용합니다.
void ProcessArrayData(IList almostAnyTypeOfArray)
{
// Do some stuff with the IList array
}
이렇게하면 IList가 아닌 IEnumerable을 사용하지 않는 한 .NET Framework의 거의 모든 배열에서 일반 처리를 수행 할 수 있습니다.
실제로 필요한 기능의 종류에 따라 다릅니다. 대부분의 경우 List 클래스를 사용하는 것이 좋습니다. IList는 컬렉션 내에서 캡슐화하려는 매우 구체적인 규칙을 가질 수있는 사용자 지정 배열을 만들어야 할 때 가장 좋습니다. 반복하지는 않지만 .NET에서이를 목록으로 인식하려고합니다.
AList 객체를 사용하면 목록을 만들고, 목록에 항목을 추가하고, 제거하고, 업데이트하고, 색인을 생성하는 등의 작업을 수행 할 수 있습니다. List는 객체 유형을 지정하는 일반 목록을 원할 때마다 사용됩니다.
반면에 IList는 인터페이스입니다. 기본적으로 BookList라는 목록 클래스와 같은 고유 한 유형의 List를 만들려면 인터페이스를 사용하여 새 클래스에 대한 기본 메서드와 구조를 제공 할 수 있습니다. IList는 List를 구현하는 고유 한 특수 하위 클래스를 만들려는 경우를위한 것입니다.
또 다른 차이점은 IList는 인터페이스이며 인스턴스화 할 수 없다는 것입니다. List는 클래스이며 인스턴스화 할 수 있습니다. 그 뜻은:
IList<string> MyList = new IList<string>();
List<string> MyList = new List<string>