0

I am looking for some input with this error. I am clear about a few things but not sure how to fix this linq expression. This error happens for our users and I can't reproduce this problem. So I tried to find where we use distinct operator with selectmany and found one occurrence in the routine.

  var finishedReqs = allDocs.SelectMany(x => x.Reqs).Distinct().ToList();
  var finishedReqsWithDocs = finishedReqs.Where(x => x.Docs.Any());
  if (finishedReqsWithDocs.Any())
     {
     //Call another routine
     }
Exception
-----------------
Message:
Object reference not set to an instance of an object.

Stack Trace:
   at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
   at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
   at System.Linq.Enumerable.<DistinctIterator>d__81`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)

I understand that if the collection is null, SelectMany returns null instead of an empty list. And then I am confused because we do a Distinct.ToList(). Where do I need to check for nulls. Resharper tells me the first expression with Distinct.ToList() can never be null

if(finishedReqs!=null) //Resharper has squiggly lines with expression is always true
{
}
user575219
  • 2,134
  • 12
  • 48
  • 95
  • is `allDocs` a IQueryable object, for example from EntityFramework, or is it just a normal IEnumerable object? – Scott Chamberlain Jan 04 '17 at 19:35
  • Also your statement *"I understand that if the collection is null, SelectMany returns null instead of an empty list."* that is not true. if the collection is null [it throws a `ArgumentNullException`](https://msdn.microsoft.com/en-us/library/bb534336(v=vs.110).aspx#Anchor_1). – Scott Chamberlain Jan 04 '17 at 19:37
  • It is a List – user575219 Jan 04 '17 at 19:37
  • ok thanks for correcting me..But what could be the problem? Any ideas. In a sense it is returning a null exception. Object reference not set to an instance of an object – user575219 Jan 04 '17 at 19:39
  • Add a where filter before the select many. Check that reqs is not null. I had written an extension method to return empty collection is collection if null for situations like this. – Nkosi Jan 04 '17 at 19:41
  • Check if one of the item in allDocs isn't null – Paweł Łukasik Jan 04 '17 at 19:42
  • @Nkosi: So you think in this line var finishedReqs = allDocs.SelectMany(x => x.Reqs).Distinct().ToList(); Reqs could be null? – user575219 Jan 04 '17 at 19:42

2 Answers2

6

It is not finishedReqs that is null, it is one of the entries inside of allDocs that is null.

If you look at the stack trace the top layer is

at System.Linq.Enumerable.d__14`2.MoveNext()

That means it is failing inside of Enumerable.SelectManyIterator. Somewhere in allDocs it is holding a null Document object.

If the error was instead that x.Reqs was null the top layer of your exception would be located inside the anonymous lambda expression in your code.

The way to fix it is exclude any null documents before you do the SelectMany

allDocs.Where(x=> x != null).SelectMany(x => x.Reqs).Distinct().ToList();
marc_s
  • 675,133
  • 158
  • 1,253
  • 1,388
Scott Chamberlain
  • 116,967
  • 28
  • 260
  • 389
  • But why is it complaning about Distinct..at System.Linq.Enumerable.d__81`1.MoveNext() – user575219 Jan 04 '17 at 19:45
  • Thank you. Can I mark both as answers? – user575219 Jan 04 '17 at 19:52
  • Because the thing that actually fires the request is the .ToList() because both `SelectMany()` and `Distinct()` are lazily evaluated. so when you go to actually perform the evaluation it has to travel through the `.ToList()` (your bottom layer), call the List constructor (the next layer), evaluate the enumarable passed in to the constructor (the layer with the `.Distinct()` because that is the outer most thing), then process the SelectMany. – Scott Chamberlain Jan 04 '17 at 19:52
  • @user575219 Honestly the answer you picked is wrong, it will still give the error because it is not `Reqs` that is null, it is `x` and he never checks for that.. – Scott Chamberlain Jan 04 '17 at 19:55
  • Ok I see what you are saying. – user575219 Jan 04 '17 at 19:56
  • Thank you. I was inclined towards this. And this may be can happen sometimes – user575219 Jan 04 '17 at 19:58
  • I did both. allDocs.Where(x=> x != null).Where(x => x.Reqs != null).SelectMany(x => x.Reqs).Distinct().ToList(); May be I could combine both the Where to allDocs.Where(x => x != null && x.Reqs!=null) – user575219 Jan 04 '17 at 20:01
  • Yes, you could combine the Where clauses if you wanted, but it does not really cause much overhead so its fine to leave them separate if you find it more readable. – Scott Chamberlain Jan 04 '17 at 21:48
0

I guess Reqs collection of one of the documents is null. Try check for null like this:

var finishedReqs = allDocs.SelectMany(x => x.Reqs ?? new Request[0]).Distinct().ToList();