2
votes

I sometimes use LINQ constructs in my C# source. I use VS 2010 with ReSharper. Now I'm getting "Possible multiple enumeration of IEnumerable" warning from ReSharper.

I would like to refactor it according to the best practices. Here's briefly what it does:

IEnumerable<String> codesMatching = from c in codes where conditions select c;
String theCode = null;
if (codesMatching.Any())
{
  theCode = codesMatching.First();
}
if ((theCode == null) || (codesMatching.Count() != 1))
{
  throw new Exception("Matching code either not found or is not unique.");
}
// OK - do something with theCode.

A question: Should I first store the result of the LINQ expression in a List? (I'm pretty sure it won't return more than a couple of rows - say 10 at the most.)

Any hints appreciated.

Thanks Pavel

3
You can use FirsOrDefault or SingleOrDefaultvmeln
FirstOrDefault() would miss the case of multiple matches, but SingleOrDefault() would do the trick. Thanks @VolodymyrMelnychukPavel Foltyn

3 Answers

4
votes

Since you want to verify if your condition is unique, you can try this (and yes, you must store the result):

var codes = (from c in codes where conditions select c).Take(2).ToArray();
if (codes.Length != 1)
{
  throw new Exception("Matching code either not found or is not unique.");
}

var code = codes[0];
3
votes

Yes, you need to store result as List\Array, and then use it. In that case it won't enumerate it a couple of times.

In your case if you need to be sure that there is just one item that satisfy condition, you can use Single - if there will be more than one item that satisfy conditions it will throw exception. If there will be no items at all, it also throw exception.

And your code will be easier:

string theCode = (from c in codes where conditions select c).Single();

But in that case you can't change exception text, or you need to wrap it into own try\catch block and rethrow it with custom text\exception

2
votes

Finalizing enumerable with .ToList()/.ToArray() would get rid of the warning, but to understand if it is better than multiple enumerations or not would depend on codes and conditions implementations. .Any() and .First() are lazy primitives and won't execute past the first element and .Count() might not be hit at all, hence converting to a list might be more wasteful than getting a new enumerator.