Reputation: 2984
I'm using Linq to filter Data I get from the database. Due to design choices made 1 method returns me an IEnumerable<int>
which I then use for a linq statement to see which IDs are permitted to be returned (code follows below). My question here is as I'm not seeing anything there in the documentation: Does the Contains method implicitly cast the IEnumerable to a List for the statement to be executed? (If so the question is if using List in the first place instead of IEnumerable is better).
Code Example
private List<MyData> GetAllPermittedData()
{
IEnumerable<int> permitteddIds = GetPermittedIDs();
return (from a in MyDataHandler.GetAllData() where permittedIds.Contains(a.Id)
select a);
}
Like I asked above I'm not sure if the Contains
part implicitly converts permittedIds into a List<int>
(for/inside the use of the Contains statement). If this is the case then a followup question would be if it is not better to already use the following statement instead (performance-wise):
private List<MyData> GetAllPermittedData()
{
List<int> permitteddIds = GetPermittedIDs().ToList();
return (from a in MyDataHandler.GetAllData() where permittedIds.Contains(a.Id)
select a);
}
Upvotes: 0
Views: 979
Reputation: 20780
The Contains
method may try to cast the passed IEnumerable<T>
to IList<T>
or to ICollection<T>
. If the cast succeeds, it may directly use the methods of IList<T>
, otherwise it will enumerate over the full sequence.
Note that I am writing may because this is implementation-specific and it is not specified in the docs. As such, it could be different across .NET versions and also in alternative implementations such as Mono.
Your advantage by providing only an IEnumerable<T>
is that you have more freedom to exchange the object returned from that property without changing the public interface. The performance cost of the attempted cast to IList<T>
or similar should be negligible.
In any case, this way is more performant than your suggestion of calling ToList
, as that will actually create a new List<T>
and copy all items from the enumeration into it.
Upvotes: 0
Reputation: 141703
The LINQ operator will attempt to cast it to ICollection<T>
first. If the cast succeeds, it uses that method. Since List<T>
implements this interface, it will use the list's contain method.
Note that if you use the overload that accepts an IEqualityComparer
, it must iterate over the enumerable and the ICollection
shortcut is not taken.
You can see this implementation in the .NET Framework reference source:
public static bool Contains<TSource>(this IEnumerable<TSource> source, TSource value) {
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null) return collection.Contains(value);
return Contains<TSource>(source, value, null);
}
Jon Skeet also has a good (and lengthy) blog series called "Reimplementing LINQ" where he discusses the implementation in depth. He specifically covers Contains
in part 32 of his blog.
Upvotes: 3
Reputation: 1048
Contains
exists as an extension method for IEnumerable<T>
. But you con't need to convert your IEnumerable to a List<T>
with ToList()
, you could simply use that IEnumerable<T>
to fill a HashSet<T>
:
var permitteddIds = new HashSet<int>(GetPermittedIDs());
Upvotes: -1