C#에서 List와 IList의 가장 큰 차이점은, List는 인덱스를 통해 접근할 수 있는 객체 목록을 나타내는 구체 클래스라는 점이고, IList는 동일한 기능을 추상화한 인터페이스라는 점입니다. IList 인터페이스는 ICollection과 IEnumerable이라는 두 인터페이스를 상속받습니다.
List와 IList는 모두 객체 집합을 표현하는 데 사용되며, 정수·문자열 등 다양한 타입의 객체를 저장할 수 있습니다. 요소를 삽입하거나 제거하고, 검색 및 정렬하는 메서드도 함께 제공합니다. 결국 List는 IList 인터페이스를 실제로 구현한 구체 타입이라고 정리할 수 있습니다.
List와 IList의 주요 차이점
- 선언 형태: List는 클래스이고, IList는 인터페이스입니다.
- 인스턴스 생성: List는 new 키워드로 직접 인스턴스를 만들 수 있지만, IList는 인터페이스이므로 직접 인스턴스화할 수 없습니다.
- 상속 관계: List는 IList, ICollection, IEnumerable 인터페이스를 구현합니다.
- 유연성: 변수를 IList 타입으로 선언하면 List뿐 아니라 다른 IList 구현체로도 손쉽게 교체할 수 있어 코드 유연성이 높아집니다.
예제 1: IList는 직접 인스턴스화할 수 없다
using System;
using System.Collections.Generic;
namespace DemoApplication{
class Demo{
static void Main(string[] args){
// 컴파일 오류 발생: 인터페이스는 인스턴스를 생성할 수 없음
IList<string> ilist = new IList<string>();
ilist.Add("Mark");
ilist.Add("John");
foreach (string list in ilist){
Console.WriteLine(list);
}
}
}
}위 코드처럼 인터페이스인 IList를 new 키워드로 인스턴스화하려고 하면 컴파일 오류가 발생합니다. 인터페이스는 구현 내용을 가지지 않는 추상적인 규약(계약)이기 때문입니다.
예제 2: List를 사용한 올바른 방법
using System;
using System.Collections.Generic;
namespace DemoApplication{
class Demo{
static void Main(string[] args){
// IList 참조 변수에 List 인스턴스를 할당 (정상 동작)
IList<string> ilist = new List<string>();
ilist.Add("Mark");
ilist.Add("John");
// List 타입으로 직접 선언
List<string> list = new List<string>();
list.Add("Mark");
list.Add("John");
foreach (string lst in ilist){
Console.WriteLine(lst);
}
foreach (string lst in list){
Console.WriteLine(lst);
}
Console.ReadLine();
}
}
}실행 결과
위 코드를 실행하면 다음과 같은 결과가 출력됩니다.
Mark John Mark John
그렇다면 어떤 것을 사용해야 할까?
클래스 내부에서 컬렉션을 직접 생성하고 관리하는 경우에는 List를 사용하는 것이 간단하고 효율적입니다. 반면, 메서드의 매개변수나 반환 타입처럼 외부에 노출되는 부분에서는 IList로 선언하는 것이 좋습니다. 이렇게 하면 구현체를 자유롭게 교체할 수 있어 확장성과 테스트 용이성이 높아지며, "구현이 아닌 인터페이스에 의존하라"는 객체 지향 설계 원칙에도 부합합니다.