IEnumerable <T>보다 List <T>를 사용해야하는 이유는 무엇입니까?


24

내 ASP.net MVC4 웹 응용 프로그램에서 IEnumerables를 사용하여 구현이 아닌 인터페이스로 프로그래밍하기 위해 만트라를 따르려고합니다.

Return IEnumerable(Of Student)

vs

Return New List(Of Student)

사람들은 IEnumerable이 아닌 List를 사용하라고 말하고 있습니다. 목록은 쿼리를 강제로 실행하고 IEumerable은 그렇지 않기 때문입니다.

이것이 가장 좋은 방법입니까? 대안이 있습니까? 인터페이스를 사용할 수있는 콘크리트 물체를 사용하면 이상한 느낌이 듭니다. 이상한 느낌이 정당합니까?


2
먼저 쿼리를 강제로 실행하는 것이 좋은 이유는 무엇입니까? 둘째, 이러한 기술적 고려 사항에 장점이 있는지 평가하기 위해 데이터베이스 호출을 모니터링하고 프로파일 링해야합니다.
user16764

2
모델이 완료되고 뷰를로드 할 수 있도록 모든 쿼리를 실행해야한다고합니다. 즉,보기는 모든 것을 받고 데이터베이스를 쿼리하지 않아야합니다.
Rowan Freeman

3
StackOverflow 질문 은 꽤 잘 다룹니다.
Karl Bielefeldt

좋은 대답이지만 MVC와의 관련성을 알고 싶습니다. 모든 쿼리가 적시에 실행되도록 뷰에 IEnumerable을 제공 할 수없는 이유는 무엇입니까?
Rowan Freeman

2
"모델이 수행되고 뷰를로드 할 수 있도록 모든 쿼리를 실행해야한다고한다. 즉, 뷰는 모든 것을 수신해야하고 데이터베이스를 쿼리하지 않아야한다." 말도 안 돼요 IEnumerable을 전달하면 뷰가 데이터베이스를 쿼리하는지 여부를 알지 못하거나 신경 쓰지 않습니다. 그리고 그렇게해야합니다.
user16764

답변:


21

하고있는 경우가 있습니다 ToList()쿼리가 시간에 당신이 그들을 기대하는 순서대로 실행 확인하는 것이 중요 할 수 있습니다 LINQ 쿼리에 있습니다. 그러나 이러한 시나리오는 드물며 진정으로 실행될 때까지 아무도 걱정하지 않아도됩니다.

간단히 말해, IEnumerable반복이 필요할 때만 사용 IList하고 직접 색인을 작성하고 동적 크기의 배열이 필요할 때 사용하십시오 (고정 크기 배열에서 색인을 생성 해야하는 경우 표준 배열을 사용하십시오).

실행 시간의 일에 관해서는, 당신은 항상 같은 목록을 사용할 수 있습니다 IEnumerable그래서를 돌려 주시기 변수 IEnumerable을 수행하여 .ToList();int로서 매개 변수에, 또는 통과 IEnumerable실행하여 .ToList()IEnumerable이 바로 그때 강제로 실행합니다. 강제로 실행을 .ToList()할 때마다 방금 수행 한 IEnumerable변수 에 매달리지 않고 다시 실행하지 않으면 LINQ 쿼리의 반복이 불필요하게 두 배가됩니다.

MVC와 관련하여 여기에 특별히 주목할 것은 없습니다. 그것은 .NET의 나머지 부분과 동일한 실행 시간 규칙을 따를 것입니다. 이전의 지연된 실행 의미로 인해 혼란스러워하는 사람이있을 수 있다고 생각합니다. 아니. 지연된 실행 시맨틱은 처음에는 모든 사람을 혼란스럽게합니다 (그리고 나중에는 좋은 결과를 위해 터치하기 까다로울 수 있습니다). 그러나 LINQ 쿼리가 두 번 실행되지 않거나 다른 코드와 비교하여 특정 순서로 실행되도록 요구 할 때까지 걱정하지 마십시오.이 시점에서 변수를 자신에게 할당하십시오. 강제로 실행하면 괜찮을 것입니다.


IEnumerables를 보는 것이 좋지 않습니까? 뷰가 쿼리를받을 때까지 쿼리가 실행되도록 목록을 제공해야합니까?
Rowan Freeman

@RowanFreeman 방금 이것에 답하기 위해 편집을 추가했습니다. 나는 당신이 완전히 이해하지 못한 무언가에 부딪친 사람을 가지고 있다고 생각합니다. 의미론.
Jimmy Hoffa

좋은 대답입니다. 실제로 실제로 .ToList ()를 사용해야합니까? 지금까지 내 응용 프로그램은 IEnumerables 만 사용하고 모델에서보기로 전달하여 정상적으로 작동합니다. 목록 없음 또는 .ToList (). 내 질문은 기능 중 하나가 아닙니다. 내 응용 프로그램이 작동한다는 것을 알고 있습니다. 내 질문은 모범 사례 중 하나입니다.
Rowan Freeman

4
@RowanFreeman 모범 사례는 여전히 요구 사항을 충족하는 최소 인터페이스를 사용하는 것입니다. IEnumerable은 현재이 작업을 수행하므로 변경에 대해 걱정하지 마십시오. 즉, 3 ~ 10 번 쿼리를 실행하고 이유를 이해하지 못하거나 삽입 전에 쿼리가 실행되어 나중에 실행되기를 기대하는 경우가 있습니다. 이는 인식해야 할 시간입니다. ()는 원할 때 강제로 실행되며 LINQ 쿼리에서 IEnumerable을 여러 번 반복하면 전체 쿼리가 여러 번 실행됩니다. 이러한 이벤트가 발생할 때 실행 문제를 해결하십시오
Jimmy Hoffa

1
List--passing을 사용해서는 안됩니다 List. 목록의 내용이 수정 될 것임을 암시합니다. 컬렉션을 반환하려면을 사용하십시오 IReadOnlyCollection. List메소드 내에서 사용하고 목록을 수정하는 메소드 간 교환을위한 것입니다. 그게 다야!
ErikE

7

두 가지 문제가 있습니다.

IENumerable<Data> query = MyQuery();

//Later
foreach (Data item in query) {
  //Process data
}

"프로세스 데이터"루프에 도달 할 때까지 쿼리가 더 이상 유효하지 않을 수 있습니다. 예를 들어, 이미 Dispose 된 DataContext에서 쿼리를 실행중인 경우 코드에서 예외가 발생합니다. 쿼리를 만든 위치와 다른 컨텍스트에서 쿼리를 처리 할 때 이러한 종류의 문제는 매우 혼란스러워집니다.

두 번째 문제는 "프로세스 데이터"루프가 완료 될 때까지 연결이 해제되지 않는다는 것입니다. "프로세스 데이터"가 복잡한 경우에만 문제가됩니다. 이것은 http://msdn.microsoft.com/en-us/library/bb386929.aspx 에서 언급됩니다 .

Q. 데이터베이스 연결이 얼마 동안 열려 있습니까?

A. 쿼리 결과를 사용할 때까지 연결은 일반적으로 열려 있습니다. 모든 결과를 처리하는 데 시간이 걸리고 결과를 캐싱하는 것이 아니라면 ToList를 쿼리에 적용하십시오. 각 개체가 한 번만 처리되는 일반적인 시나리오에서는 스트리밍 모델이 DataReader와 LINQ to SQL 모두에서 우수합니다.

따라서 이러한 문제 때문에을 호출하여 쿼리가 실제로 실행되도록 권장하고 있습니다 ToList(). 그러나 Jimmy가 제안한 것처럼 List를 IEnumerable로 반환하지 못하게하는 것은 없습니다.

일반적으로 IEnumerable을 두 번 이상 반복하지 않는 것이 좋습니다. 코드 소비자가이 규칙을 준수한다고 가정하면 누군가 쿼리를 두 번 실행하여 데이터베이스에 두 번 충돌 할 우려는 없습니다.


1

IEnumerable조기 열거의 또 다른 이점은 적절한 위치에서 예외가 발생한다는 것입니다. 이것은 디버깅을 돕습니다.

예를 들어, Razor 뷰 중 하나에 교착 상태 예외가 발생하면 데이터 액세스 방법 중 하나에서 예외가 발생한 것처럼 명확하지 않습니다.


IEnumerable던질 수있는를 반환하는 모든 메소드 는 실수를 저지른 것 같습니다. 지연된 IEnumerable메소드는 두 가지로 나뉘어 야합니다. 지연되지 않은 메소드 중 하나는 매개 변수를 확인하고 필요한 경우 (예 : 널 인수로 인해) 던집니다. 그런 다음 개인 구현에 대한 호출을 반환합니다. 되는 연기를. 내 의견은 당신의 대답과 확률에 완전히 생각하지 않지만, 당신이 당신의 대답에 중요한 측면, 탈락했다고 생각하십니까 사용의 의미 론적 의미를 IEnumerableN 대 List(돌연변이) 대 IReadOnlyCollection(아무런 혜택 연기) .
ErikE
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.