your programing

IEnumerable vs List-무엇을 사용합니까?

lovepro 2020. 10. 2. 22:59
반응형

IEnumerable vs List-무엇을 사용합니까? 어떻게 작동합니까?


Enumerators 및 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. 를 사용 IEnumerable하면 "sel"을 디버깅하고 검사 할 때 IEnumerable 인 "inner", "outer", "innerKeySelector"및 "outerKeySelector"와 같은 흥미로운 멤버가있는 것으로 나타났습니다.이 마지막 2 개가 나타납니다. 대의원이 되십시오. "inner"멤버는 "Animal"인스턴스가 아니라 "Species"인스턴스가 있습니다. 이것은 저에게 매우 이상했습니다. "외부"멤버는 "Animal"인스턴스를 포함합니다. 나는 두 대표가 어느 쪽이 들어오고 나가는지를 결정한다고 생각한다.

  2. "Distinct"를 사용하면 "inner"에 6 개의 항목이 포함되어 있지만 (2 개만 Distinct이므로 올바르지 않음) "outer"에는 올바른 값이 포함되어 있습니다. 다시 말하지만 위임 된 메서드가 이것을 결정하지만 이것은 IEnumerable에 대해 아는 것보다 약간 더 많습니다.

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

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

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

가능하다면 IEnumerable의 사용을 설명하는 링크를 조금만 설명하거나 링크를 던져주세요.


IEnumerable동작을 설명하는 반면 List는 해당 동작의 구현입니다. 를 사용 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와 Hyena는 각각 단일 SQL 쿼리 로 변환되고 데이터베이스는 관련된 행만 반환합니다. 그러나에서 List를 반환했다면 AllSpotted()데이터베이스가 실제로 필요한 것보다 훨씬 더 많은 데이터를 반환 할 수 있기 때문에 느리게 실행될 수 있으며 클라이언트에서 필터링을 수행하는 데주기를 낭비 할 수 있습니다.

프로그램에서 쿼리를 목록으로 변환하는 것을 끝까지 연기하는 것이 더 나을 수 있으므로 Leopards와 Hyena를 두 번 이상 열거 할 경우 다음과 같이합니다.

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

다음은 Claudio Bernasconi의 TechBlog에 의해 작성된 매우 좋은 기사입니다. IEnumerable, ICollection, IList 및 List를 사용하는 경우

Here some basics points about scenarios and functions:

여기에 이미지 설명 입력 여기에 이미지 설명 입력


A class that implement IEnumerable allows you to use the foreach syntax.

Basically it has a method to get the next item in the collection. It doesn't need the whole collection to be in memory and doesn't know how many items are in it, foreach just keeps getting the next item until it runs out.

This can be very useful in certain circumstances, for instance in a massive database table you don't want to copy the entire thing into memory before you start processing the rows.

Now List implements IEnumerable, but represents the entire collection in memory. If you have an IEnumerable and you call .ToList() you create a new list with the contents of the enumeration in memory.

Your linq expression returns an enumeration, and by default the expression executes when you iterate through using the foreach. An IEnumerable linq statement executes when you iterate the foreach, but you can force it to iterate sooner using .ToList().

Here's what I mean:

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 ) ...

Nobody mentioned one crucial difference, ironically answered on a question closed as a duplicated of this.

IEnumerable is read-only and List is not.

See Practical difference between List and IEnumerable


The most important thing to realize is that, using Linq, the query does not get evaluated immediately. It is only run as part of iterating through the resulting IEnumerable<T> in a foreach - that's what all the weird delegates are doing.

So, the first example evaluates the query immediately by calling ToList and putting the query results in a list.
The second example returns an IEnumerable<T> that contains all the information needed to run the query later on.

In terms of performance, the answer is it depends. If you need the results to be evaluated at once (say, you're mutating the structures you're querying later on, or if you don't want the iteration over the IEnumerable<T> to take a long time) use a list. Else use an IEnumerable<T>. The default should be to use the on-demand evaluation in the second example, as that generally uses less memory, unless there is a specific reason to store the results in a list.


The advantage of IEnumerable is deferred execution (usually with databases). The query will not get executed until you actually loop through the data. It's a query waiting until it's needed (aka lazy loading).

If you call ToList, the query will be executed, or "materialized" as I like to say.

There are pros and cons to both. If you call ToList, you may remove some mystery as to when the query gets executed. If you stick to IEnumerable, you get the advantage that the program doesn't do any work until it's actually required.


I will share one misused concept that I fell into one day:

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() );

Expected result

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

Actual result

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

Explanation

As per other answers, the evaluation of the result was deferred until calling ToList or similar invocation methods for example ToArray.

So I can rewrite the code in this case as:

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() );

Play arround

https://repl.it/E8Ki/0


If all you want to do is enumerate them, use the IEnumerable.

Beware, though, that changing the original collection being enumerated is a dangerous operation - in this case, you will want to ToList first. This will create a new list element for each element in memory, enumerating the IEnumerable and is thus less performant if you only enumerate once - but safer and sometimes the List methods are handy (for instance in random access).


In addition to all the answers posted above, here is my two cents. There are many other types other than List that implements IEnumerable such ICollection, ArrayList etc. So if we have IEnumerable as parameter of any method, we can pass any collection types to the function. Ie we can have method to operate on abstraction not any specific implementation.


There are many cases (such as an infinite list or a very large list) where IEnumerable cannot be transformed to a List. The most obvious examples are all the prime numbers, all the users of facebook with their details, or all the items on ebay.

The difference is that "List" objects are stored "right here and right now", whereas "IEnumerable" objects work "just one at a time". So if I am going through all the items on ebay, one at a time would be something even a small computer can handle, but ".ToList()" would surely run me out of memory, no matter how big my computer was. No computer can by itself contain and handle such a huge amount of data.

[Edit] - Needless to say - it's not "either this or that". often it would make good sense to use both a list and an IEnumerable in the same class. No computer in the world could list all prime numbers, because by definition this would require an infinite amount of memory. But you could easily think of a class PrimeContainer which contains an IEnumerable<long> primes, which for obvious reasons also contains a SortedList<long> _primes. all the primes calculated so far. the next prime to be checked would only be run against the existing primes (up to the square root). That way you gain both - primes one at a time (IEnumerable) and a good list of "primes so far", which is a pretty good approximation of the entire (infinite) list.

참고URL : https://stackoverflow.com/questions/3628425/ienumerable-vs-list-what-to-use-how-do-they-work

반응형