Can someone explain me why the following LINQ query throws an InvalidOperationException?
(Don't say that the list has no elements,the value that I'm 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 appears only when I call NewMethod inside my lambda expession.
If do this 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 the value exists in the collection when it crashes
PS
The problem is not the random variable,I removed the parameter and create a new local random inside the method but the problem still exists
It turns out that you don't need the loop to make it crash. If you run the program many times you will get the 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;
}
}
Fixing LINQ Error “Sequence contains no elements” [C#, LINQ] When you query a LINQ data source with the Single() method call you may get the exception “System.InvalidOperationException: Sequence contains no elements”. This exception is raised when there are no records that matches to the criteria specified in the LINQ query.
When you query a LINQ data source with the Single () method call you may get the exception “System.InvalidOperationException: Sequence contains no elements”. This exception is raised when there are no records that matches to the criteria specified in the LINQ query.
As per the exception - The sequence returned in step1 contains no elements. Single () tries to retrieve an element from the sequence returned in step1 which contains no elements. Since Single () is not able to fetch a single element from the sequence returned in step1, it throws an error.
This exception is raised when there are no records that matches to the criteria specified in the LINQ query. For example the following LINQ query raises the exception if the where criteria does not match with any records in the data source To solve the problem replace the method Single () call with SingleOrDefault () method.
@Oleg is right, but here's why it's the problem.
Where
scans through the list looking for elements that match the given criteria. In this case the criteria changes for each element. If you made the problem smaller, say an array of 5 elements:
List<Int32> (5 items)
1
2
3
4
5
And then looped through looking for a value that matches 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 item match that particular random number, so no item matched the criteria and First
throws an exception!
The fix, as you have discovered, is to generate the random number before the enumeration:
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's a bit misleading to use maxValue
here:
Enumerable.Range(minValue, maxValue)
Since the second parameter to Enumerable.Range
is the length of the resulting collection, not the max value. In this case it works because you're starting at 1 but the results would be unexpected if you used, say 99 and 100 - you'd get a range from 99 to 198.
It's because NewMethod invokes on every iteration and every time generates new random number.
But in this code at first generates number and then compares to each element of numbers collection.
int temp=NewMethod(minValue, maxValue, random);
int x = numbers.Where(v => v == temp).First();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With