Why am I getting "The sequence contains no elements"?

NOTE: see the edits below. I am an idiot.

I had the following code to handle a 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 it worked just fine, except that he could not handle cases where there is a tag called "Foo" and the list contains "foo". In other words, this is not case insensitive comparison.

I modified the test to use case insensitive comparison:

 var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.Equals(n, StringComparison.InvariantCultureIgnoreCase))); 

... and suddenly I get an exception that is thrown when starting foreach (and throws MoveNext on) newTagNames. An exception:

The sequence has no elements.

I am confused by this. Why foreach insist that the sequence is nonempty? I would expect to see this error if I called First() , but not when using foreach ?


EDIT : additional information.

With a minute it gets weirder. Since my code is in an asynchronous method, and I am superstitious, I decided that there is too much β€œdistance” between the point at which the exception occurs and the point at which it was detected and reported. So I put a try / catch around the abusive code, hoping to verify that the exceptional exception was really what I thought it was.

So, now I can go into the debugger to the foreach line, I can check that the sequence is empty, and I can perform a step up to a bit where the debugger selects the word "in". One more step, and I'm in my exception handler.

But , not the exception handler that I just added, no! It gets into my external exception handler without visiting my newly added! It does not match catch (Exception ex) and does not match a simple catch value. (I also put finally and confirmed that he is visiting this at the exit).

I always believed that an Exception handler, such as those, would fall into any exception. Now i'm scared. I need an adult.


EDIT 2 :

OK, so um, false alarm ... The exception was not caught by the local try / catch simply because it was not raised by the code that I thought. As I said above, I watched how execution in the debugger proceeds from "in" to foreach directly to an external exception handler, therefore, my (incorrect) assumption is that there was an error. However, with an empty enumeration, it was just the last statement executed inside the function, and for some reason the debugger did not show me the way out of the function or the execution of the next statement at the point of call - which was in fact causing an error.

I apologize to everyone who answered, and if you want to create an answer saying that I am an idiot, I will gladly accept it. That is, if I ever show my face again on SO ...

+4
source share
2 answers

This is not so correct or clean, but how it works:

 var newTagNames = tagNames.Where(n => !allTags.Any(t => t.Name.ToUpper() == n.ToUpper())); 
0
source

Exception handling is the pleasure of pending actions. The Enumerable.Where method (and most linq methods) does not execute until the request is numbered.

 IEnumerable<int> query = Enumerable.Empty<int>(); int myNum = 0; try { query = Enumerable.Range(1, 100).Where(i => (i/myNum) > 1); } catch { Console.WriteLine("I caught divide by zero"); //does not run } foreach(int i in query) //divide by zero exception thrown { //.. } 

In your particular case:

 IEnumberable<string> tagNames = GetTagNames(); 

I set GetTagNames have Enumerable.First or Enumerable.Single inside somewhere. If the GetTagNames result is delayed, you must list this result to get an exception. This is why commentators recommend that you call ToList based on GetTagNames results - list it and get an exception before you use tags in a complex query.

0
source

Source: https://habr.com/ru/post/1446053/


All Articles