Logo




Subscribe:
RSS 2.0 | Atom 1.0
Categories:

Sign In


[Giagnocavo]Michael::Write()

# Wednesday, September 24, 2008
Empty check on IEnumerable without consuming
One common issue with IEnumerables is that you can't find out anything about them until you use them. A frequent scenario is wanting to know if the IEnumerable is empty before you go ahead and use it. For example, you may want to write a result set to a file, but only if there's actually data.

As far as I know, the .NET Framework has no built-in classes to facilitate this, so I hacked up my own. You use it by wrapping an IEnumerable inside an EmptyCheckEnumerable. Then, when you check the IsEmpty property, it gets the enumerator and calls MoveNext once. When you then go to consume it, it intercepts the MoveNext call and simply returns the previous value. From then on, it just passes through. The result is that you don't consume the IE twice, which can be necesary for performance or other reasons.

Example:
var res = new EmptyCheckEnumerable<object>(dc.Execute<object>("SELECT * FROM foo"));
if (!res.IsEmpty) {
  // allocate resources and consume the IE - will only execute the SELECT once
}
I suggest creating a "ToEmptyCheck" extension method to flow type information.
Code:

EmptyCheckEnumerable.cs.txt (2.14 KB)
Code
Wednesday, September 24, 2008 10:11:30 PM UTC  #    Comments [8]  |  Trackback

Friday, October 10, 2008 2:54:32 PM UTC
Doesn't IEnumerable.Any() accomplish the same thing?
Friday, October 10, 2008 4:33:19 PM UTC
Hi Chuck. No, calling Enumerable.Any enumerates the enumeration and just returns after one item. So if you do:
var ie = GetExpensiveEnumerable();
if (!ie.Any()) return;
ie.ForEeach...

In the case where there are elements, you've started the enumerable twice.
Monday, October 20, 2008 3:02:25 PM UTC
Hi, I used this on a C# 2.0 site with only a couple of changes (removed use of var) so thanks for this I found it useful! Don't think C# 2.0 even has Any() which I would have settled for.
Adam B
Tuesday, March 03, 2009 1:47:10 PM UTC
How about Take(1).Count()
Tuesday, March 03, 2009 1:49:38 PM UTC
Actually, Any() is right. From MSDN:

The enumeration of source is stopped as soon as the result can be determined.
Tuesday, March 03, 2009 7:39:54 PM UTC
@Ike: Any will enumerate. Even if it stops after the first one, it's too late -- you've now got the enumerator and disposed it. See my previous comment.
Wednesday, March 04, 2009 12:09:21 AM UTC
I just read your implementation. I see that it caches the first object. I could see where that would be useful for extremely expensive enumerables, but I don't think it's good general purpose behavior. Admittedly contrived example:

//prints the first odd number if there are any even numbers in the sequence
int numbers = new[] {0, 1, 2, 3, 4};
int parity = 0;
EmptyCheckEnumerable<int> filtered = new EmptyCheckEnumerable<int>(myList.Where(a => a % 2 == parity));
if(!filtered.IsEmpty)
{
parity = 1;
Console.WriteLine(filtered.First()); //should print 1 but prints 0!
}
Wednesday, March 04, 2009 12:15:57 AM UTC
Well, there the problem is that you're using closures with mutable state. Having the enumeration depend on your current state, and then depending on that dependency just seems ripe for bugs in general.

Yes, you need to be aware what's happening if you use the cached enumerable. But if using enumerables pure, caching would not be an issue.
OpenID
Please login with either your OpenID above, or your details below.
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):

Live Comment Preview