Type compatibility and LINQ mystery
I had a block of code:
List<OneFeat> Feats;
...
List<OneFeat> Results = new List<OneFeat>(0);
foreach (OneFeat Test in Feats)
if (String.Compare(Test开发者_运维知识库.Name, Target, true) == 0)
Results.Add(Test);
return Results;
Resharper offered:
List<OneFeat> Results = new List<OneFeat>(0);
Results.AddRange(Feats.Where(Feat => String.Compare(Feat.Name, Target, true) == 0));
return Results;
Which of course worked. However, it's creating a list and adding it to an empty list so I tried to simplify it to:
return Feats.Where(Feat => String.Compare(Feat.Name, Target, true) == 0));
Which won't compile because it wants a cast. If I add the cast it fails at runtime.
Is there any way to code this without copying the list of results?
Aha, Lists vs Enumerations!
However, it's creating a list and adding it to an empty list
No, it's not creating a list - otherwise your final line would work. It's adding an IEnumerable
to a list.
A Where
operator returns an IEnumerable
, which is not a 'list' - it's more like a loose, iterable, and non-concrete collection.
When you call AddRange
then this collection is iterated and added to the empty list. I would expect that this is very similar to simply calling ToList
on the result.
The concept is a little hard to grasp at first, but think of an IEnumerable
as a function to return data rather than a collection of data. If you made a list of items filtered by a where clause, and then change the values of those items, the list doesn't change - it's already been created, and items won't be removed or added based on those values (unless you explicitly do so).
With an enumeration, however, the items are retrieved from the underlying collection lazily and only when required. So you can make an enumeration of items filtered by a where clause across a collection, then change all the values so none match the filter, and when you retrieve from the enumeration it will be empty.
or you could add .ToList() in the end of Where statement as follows:
return Feats.Where(Feat => String.Compare(Feat.Name, Target, true) == 0)).ToList();
If you just want to enumerate over the list of Feats that match then change the return type to IEnumerable<OneFeat>
. If you must return an actual list, it has to be copied since the original Feats object does not represent the subset of feats that match the Test.Name.
精彩评论