Why do I get "Sequence contains no elements"?
- by Gary McGill
NOTE: see edits at bottom. I am an idiot.
I had the following code to process set of tag names and identify/process new ones:
IEnumberable<string> tagNames = GetTagNames();
List<Tag> allTags = GetAllTags();
var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name == n));
foreach (var tagName in newTagNames)
{
// ...
}
...and this worked fine, except that it failed to deal with cases where there's a tag called "Foo" and the list contains "foo". In other words, it wasn't doing a case-insensitive comparison.
I changed the test to use a case-insensitive comparison, as follows:
var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.Equals(n, StringComparison.InvariantCultureIgnoreCase)));
... and suddenly I get an exception thrown when the foreach runs (and calls MoveNext on) newTagNames. The exception says:
Sequence has no elements
I'm confused by this. Why would foreach insist on the sequence being non-empty? I'd expect to see that error if I was calling First(), but not when using foreach?
EDIT: more info.
This is getting weirder by the minute. Because my code is in an async method, and I'm superstitious, I decided that there was too much "distance" between the point at which the exception is raised, and the point at which it's caught and reported. So, I put a try/catch around the offending code, in the hope of verifying that the exception being thrown really was what I thought it was.
So now I can step through in the debugger to the foreach line, I can verify that the sequence is empty, and I can step right up to the bit where the debugger highlights the word "in". One more step, and I'm in my exception handler.
But, not the exception handler I just added, no! It lands in my outermost exception handler, without visiting my recently-added one! It doesn't match catch (Exception ex) and nor does it match a plain catch. (I did also put in a finally, and verified that it does visit that on the way out).
I've always taken it on faith that an Exception handler such as those would catch any exception. I'm scared now. I need an adult.
EDIT 2:
OK, so um, false alarm... The exception was not being caught by my local try/catch simply because it was not being raised by the code I thought. As I said above, I watched the execution in the debugger jump from the "in" of the foreach straight to the outer exception handler, hence my (wrong) assumption that that was where the error lay. However, with the empty enumeration, that was simply the last statement executed within the function, and for some reason the debugger did not show me the step out of the function or the execution of the next statement at the point of call - which was in fact the one causing the error.
Apologies to all those who responded, and if you would like to create an answer saying that I am an idoit, I will gladly accept it. That is, if I ever show my face on SO again...