The sequence contains no elements.

Can someone explain to me why the following LINQ query raises an InvalidOperationException?
(Don’t say that there are no elements in the list, the value I am looking for always exists in the collection)

class Program { static int lastNumber; static void Main() { int loopCount = 100; int minValue = 1; int maxValue = 10000; var numbers = Enumerable.Range(minValue, maxValue).ToList();//or ToArray(); Random random = new Random(); for (int i = 0; i < loopCount; i++) { //.First() throws the exception but it is obvious that the value exists in the list int x = numbers.Where(v => v == NewMethod(minValue, maxValue, random)).First(); } Console.WriteLine("Finished"); Console.ReadLine(); } private static int NewMethod(int minValue, int maxValue, Random random) { var a1 = random.Next(minValue + 1, maxValue - 1); lastNumber = a1; return a1; } } 

The problem only occurs when calling NewMethod inside my lambda expiration.
If it works,

 int temp=NewMethod(minValue, maxValue, random); int x = numbers.Where(v => v == temp).First(); 

I added the lastNumber field to help debug the code, you can see that this value exists in the collection when it causes a crash

PS
The problem is not a random variable, I deleted the parameter and created a new local random case inside the method, but the problem still exists

Update

Turns out you don't need a loop to make it crash. If you run the program many times, you will get an error again.

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; class Program { static int lastNumber; static void Main() { int minValue = 1, maxValue = 100000; var numbers = Enumerable.Range(minValue, maxValue).ToArray(); //Crashes sometimes int x = numbers.Where(v => v == NewMethod(minValue, maxValue)).First(); Console.WriteLine("Finished"); Console.ReadLine(); } private static int NewMethod(int minValue, int maxValue) { Random random = new Random(); var a1 = random.Next(minValue + 1, maxValue - 1); lastNumber = a1; return a1; } } 
+5
source share
2 answers

@Oleg is right, but that is why this is a problem.

Where scans a list looking for items matching specified criteria. In this case, the criteria are changed for each item. If you made the problem smaller, say an array of 5 elements:

 List<Int32> (5 items) 1 2 3 4 5 

And then it goes into cycles to find a value that corresponds to some random number (x is Item[i] and r is a random number):

 Item 1: x = 1, r = 2 // fail Item 2: x = 2, r = 3 // fail Item 3: x = 3, r = 2 // fail Item 4: x = 4, r = 3 // fail Item 5: x = 5, r = 2 // fail 

Note that no element matches this random number, so no element matches the criteria, and First throws an exception!

The fix, as you discovered, is to generate a random number before listing:

 int temp=NewMethod(minValue, maxValue, random); // say 2 Item 1: x = 1, temp = 2 // fail Item 2: x = 2, temp = 2 // success! 

Side note:

It is slightly wrong to use maxValue here:

  Enumerable.Range(minValue, maxValue) 

Since the second parameter of Enumerable.Range is the length of the resulting set, and not the maximum value. In this case, this works because you start at 1, but the results will be unexpected if you use, say, 99 and 100 - you will get a range from 99 to 198.

+5
source

This is because NewMethod calls at each iteration and generates a new random number each time.

But in this code, a number is first generated, and then compared with each element of the set of numbers.

 int temp=NewMethod(minValue, maxValue, random); int x = numbers.Where(v => v == temp).First(); 
+4
source

All Articles