If I have an anonymous type created by LINQ
var ans = from r in someList where someCondition(r) select new { r.a, r.b };
What is the best way to create an empty matching collection so I can move elements to the new collection:
var newans = ?
foreach (r in ans) { if (complicated(r)) newans.Add(r); }
Is there some way to use Enumerable.Empty<>()?
I wouldn’t use the
ans.Where(x => false).ToList()versions these iterate over all elements, which you don’t need;ans.Take(0).ToList()is a little better, as this one doesn’t actually iterate over the entire list when you’re querying over in-memory sequences (LINQ to Objects).If you are using LINQ to SomethingElse, things are a little problematic, because it might actually execute something like
SELECT TOP(0) * FROM ...orSELECT * FROM ... WHERE 1 = 0. Not good.So the following helper method will help you:
Having said that, if your only desire is to copy some elements of
ansinto a new list, you’re better of withor
If you don’t need an actual
List<T>, and anIEnumerable<T>is enough, you might get away with omitting theToListaltogether. Mind you, every time you foreach over such an enumerable,Where(a => isComplicated(a))is executed again and again. The call toToListmakes sure you only execute it once.If you don’t want this just for
List<T>, but more general, things get a lot more complicated. For example, should the method return the static type of theansvariable or its runtime type? Also, there is no such thing as a “default” version of many collections, apart from blindly callingnew C(). But that won’t work generally. It’s not possible to callnew ReadOnlyCollection<T>(), because it doesn’t exist (and the collection would be sealed anyway, so it cannot be filled). And if you’re using a HasSet, shouldn’t you be using the original’s comparer for your empty copy rather than the default comparer?However, for the simplest case, you could try:
Note that this is a compile-time solution which returns a default collection of the variable‘s type. If at all possible. For instance
ans = from r in somesource select new { ... }will have the static typeIEnumerable<...>. There’s no default instance here to create. Also, the runtime type returned byselectis private to System.Core.dll, doesn’t have a default constructor, and is a read-only cursor-like type anyway.So my opinion on this one is: don’t go there. Don’t try to over-generalize, stick to simple solutions like ToEmptyList or even better, stick to plain LINQ method chaining.