[C#] IEnumerable vs List-무엇을 사용해야합니까? 그들은 어떻게 작동합니까?

열거 자 작동 방식과 LINQ에 대한 의구심이 있습니다. 다음 두 가지 간단한 선택을 고려하십시오.

List<Animal> sel = (from animal in Animals
                    join race in Species
                    on animal.SpeciesKey equals race.SpeciesKey
                    select animal).Distinct().ToList();

또는

IEnumerable<Animal> sel = (from animal in Animals
                           join race in Species
                           on animal.SpeciesKey equals race.SpeciesKey
                           select animal).Distinct();

좀 더 일반적인 예처럼 보이도록 원래 객체의 이름을 변경했습니다. 쿼리 자체는 그렇게 중요하지 않습니다. 내가 묻고 싶은 것은 이것입니다 :

foreach (Animal animal in sel) { /*do stuff*/ }
  1. IE를 사용할 수있는 IEnumerable“sel”을 디버깅하고 검사 할 때 “inner”, “outer”, “innerKeySelector”및 “outerKeySelector”와 같은 흥미로운 멤버가있는 경우이 마지막 2 개가 나타납니다. 대의원이 될 수 있습니다. “inner”멤버에는 “Animal”인스턴스가 아니라 “Species”인스턴스가 있는데 이는 매우 이상했습니다. “outer”멤버는 “Animal”인스턴스를 포함합니다. 나는 두 대표가 어느 쪽이 들어오고 나가는지를 결정한다고 가정합니다.

  2. “Distinct”를 사용하면 “inner”에 6 개의 항목이 포함되지만 (2 개만 구분되므로 올바르지 않습니다) “outer”에 올바른 값이 포함되어 있습니다. 다시 말하지만, 위임 된 메소드가 이것을 결정하지만 IEnumerable에 대해 아는 것보다 조금 더 큽니다.

  3. 가장 중요한 것은 두 가지 옵션 중 성능면에서 가장 좋은 방법은 무엇입니까?

.ToList()? 를 통한 악 목록 변환

아니면 열거자를 직접 사용합니까?

가능하다면 IEnumerable의 사용법을 설명하는 약간의 링크를 던져주십시오.



답변

IEnumerableList는 해당 동작의 구현입니다. 을 사용할 때 IEnumerable컴파일러는 나중에 작업을 연기하여 길을 따라 최적화 할 수있는 기회를 제공합니다. ToList ()를 사용하면 컴파일러가 결과를 즉시 수정하도록합니다.

LINQ 표현식을 “스태킹”할 때마다 IEnumerable동작을 지정하여 LINQ에 평가를 연기하고 프로그램을 최적화 할 수있는 기회를주기 때문에을 사용합니다. LINQ가 데이터베이스를 열거 할 때까지 SQL을 생성하여 데이터베이스를 쿼리하지 않는 방법을 기억하십니까? 이걸 고려하세요:

public IEnumerable<Animals> AllSpotted()
{
    return from a in Zoo.Animals
           where a.coat.HasSpots == true
           select a;
}

public IEnumerable<Animals> Feline(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Felidae"
           select a;
}

public IEnumerable<Animals> Canine(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Canidae"
           select a;
}

이제 초기 샘플 ( “AllSpotted”)과 일부 필터를 선택하는 방법이 있습니다. 이제 당신은 이것을 할 수 있습니다 :

var Leopards = Feline(AllSpotted());
var Hyenas = Canine(AllSpotted());

따라서 List over를 사용하는 것이 더 빠릅 IEnumerable니까? 쿼리가 두 번 이상 실행되지 않도록하려는 경우에만 해당됩니다. 그러나 전반적으로 더 낫습니까? 위에서 Leopards와 Hyenas는 각각 단일 SQL 쿼리 로 변환되며 데이터베이스는 관련 행만 반환합니다. 그러나에서 from을 반환 한 AllSpotted()경우 데이터베이스가 실제로 필요한 것보다 훨씬 많은 데이터를 반환 할 수 있고 클라이언트에서 필터링을 수행하는주기가 낭비되므로 실행 속도가 느려질 수 있습니다.

프로그램에서는 끝까지 쿼리를 목록으로 변환하는 것을 연기하는 것이 좋습니다. 따라서 Leopards와 Hyenas를 두 번 이상 열거하려면 다음과 같이하십시오.

List<Animals> Leopards = Feline(AllSpotted()).ToList();
List<Animals> Hyenas = Canine(AllSpotted()).ToList();


답변

Claudio Bernasconi의 TechBlog는 다음과 같이 작성했습니다. IEnumerable, ICollection, IList 및 List 사용시기

시나리오 및 기능에 대한 몇 가지 기본 사항은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오
여기에 이미지 설명을 입력하십시오


답변

구현하는 클래스 IEnumerable를 사용하면 foreach구문 을 사용할 수 있습니다 .

기본적으로 컬렉션의 다음 항목을 가져 오는 방법이 있습니다. 전체 컬렉션이 메모리에있을 필요는 없으며 얼마나 많은 항목이 있는지 알지 foreach못하고 다음 항목이 계속 나올 때까지 계속 가져옵니다.

이것은 특정 상황에서 매우 유용 할 수 있습니다 (예 : 대규모 데이터베이스 테이블의 경우 행 처리를 시작하기 전에 전체 내용을 메모리에 복사하지 않으려는 경우).

이제는 List구현 IEnumerable하지만 메모리의 전체 컬렉션을 나타냅니다. 가 있고 IEnumerable호출 .ToList()하면 메모리에 열거 내용이 포함 된 새 목록을 만듭니다.

linq 표현식은 열거를 리턴하며 기본적으로을 사용하여 반복 할 때 표현식이 실행됩니다 foreach. IEnumerableLINQ 문이 실행 당신은을 반복 할 때 foreach,하지만 당신은 사용 빨리 반복을 강제 할 수 있습니다 .ToList().

여기 내가 의미하는 바가있다 :

var things =
    from item in BigDatabaseCall()
    where ....
    select item;

// this will iterate through the entire linq statement:
int count = things.Count();

// this will stop after iterating the first one, but will execute the linq again
bool hasAnyRecs = things.Any();

// this will execute the linq statement *again*
foreach( var thing in things ) ...

// this will copy the results to a list in memory
var list = things.ToList()

// this won't iterate through again, the list knows how many items are in it
int count2 = list.Count();

// this won't execute the linq statement - we have it copied to the list
foreach( var thing in list ) ...


답변

아무도 이것과 중복되는 질문에 대해 아이러니하게 대답 한 한 가지 중요한 차이점을 언급하지 않았습니다.

IEnumerable은 읽기 전용이며 List는 아닙니다.

List와 IEnumerable의 실제 차이점 보기


답변

가장 중요한 것은 Linq를 사용하여 쿼리가 즉시 평가되지 않는다는 것입니다. 단지 결과를 통해 반복하는의 일환으로 실행되는 IEnumerable<T>A의 foreach-의 어떤 모든 이상한 대표를하고 있다는 것을.

따라서 첫 번째 예 ToList에서는 쿼리 결과를 호출 하고 목록에 넣어서 즉시 쿼리를 평가 합니다.
두 번째 예는 IEnumerable<T>나중에 쿼리를 실행하는 데 필요한 모든 정보가 포함 된를 반환합니다 .

성능면에서 그 대답은 에 달려 있습니다. 결과를 한 번에 평가해야하는 경우 (예 : 나중에 쿼리하는 구조를 변경하거나 IEnumerable<T>오랜 시간이 걸리는 반복을 원하지 않는 경우 ) 목록을 사용하십시오. 그렇지 않으면를 사용하십시오 IEnumerable<T>. 결과를 목록에 저장해야하는 특별한 이유가없는 한 일반적으로 적은 메모리를 사용하므로 두 번째 예에서는 주문형 평가를 기본값으로 사용해야합니다.


답변

IEnumerable의 장점은 지연된 실행 (일반적으로 데이터베이스 사용)입니다. 실제로 데이터를 반복 할 때까지 쿼리가 실행되지 않습니다. 필요할 때까지 기다리는 쿼리입니다 (일명 지연 로딩).

ToList를 호출하면 쿼리가 실행되거나 “구체적으로 구체화”됩니다.

둘 다 장단점이 있습니다. ToList를 호출하면 쿼리가 실행될 때의 미스터리를 제거 할 수 있습니다. IEnumerable을 고수하면 실제로 필요할 때까지 프로그램이 작동하지 않는다는 이점이 있습니다.


답변

나는 하루에 빠진 잘못 사용 된 개념 하나를 공유 할 것이다.

var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"};

var startingWith_M = names.Where(x => x.StartsWith("m"));

var startingWith_F = names.Where(x => x.StartsWith("f"));


// updating existing list
names[0] = "ford";

// Guess what should be printed before continuing
print( startingWith_M.ToList() );
print( startingWith_F.ToList() );

예상 결과

// I was expecting    
print( startingWith_M.ToList() ); // mercedes, mazda
print( startingWith_F.ToList() ); // fiat, ferrari

실제 결과

// what printed actualy   
print( startingWith_M.ToList() ); // mazda
print( startingWith_F.ToList() ); // ford, fiat, ferrari

설명

다른 답변에 따라 결과 평가는 ToList예를 들어 호출 또는 유사한 호출 방법 까지 연기 ToArray됩니다.

따라서이 경우 코드를 다음과 같이 다시 작성할 수 있습니다.

var names = new List<string> {"mercedes", "mazda", "bmw", "fiat", "ferrari"};

// updating existing list
names[0] = "ford";

// before calling ToList directly
var startingWith_M = names.Where(x => x.StartsWith("m"));

var startingWith_F = names.Where(x => x.StartsWith("f"));

print( startingWith_M.ToList() );
print( startingWith_F.ToList() );

아케이드 플레이

https://repl.it/E8Ki/0