Reputation: 39058
I'm getting some unexpected behavior in my process. I'm doing the following.
IEnumerable<Thing> things = ...;
IEnumerable<Thing> subset = things.Where(a => a.SomeFlag);
String info = "null: " + (subset == null);
The above works and info tells me that the object isn't null. So I wish to check the number of the elements in subset by this.
IEnumerable<Thing> things = ...;
IEnumerable<Thing> subset = things.Where(a => a.SomeFlag);
String info = "null: " + (subset == null);
String count = subset.Count();
Now I get an exception giving me the error message:
Object reference not set to an instance of an object.
What do I miss?!
Upvotes: 5
Views: 7175
Reputation: 148980
It's possible that one of the Thing
's in subset
is null
. You can try this:
IEnumerable<Thing> subset = things.Where(a => a != null && a.SomeFlag);
Note that due to the way Linq's lazy evaluation, you won't get any exception you call .Where
because all it's doing at that point is setting up a condition for filtering the elements of things
. Only later when you call .Count
is it actually evaluating the results.
Update: With the new null-condition operator in C# 6 (also called the safe navigation or 'Elvis' operator), we can do the same thing a bit more succinctly:
IEnumerable<Thing> subset = things.Where(a => a?.SomeFlag);
Upvotes: 6
Reputation: 101652
Ok, so suppose you had the following items in things
:
Thing A SomeFlag = true
Thing B SomeFlag = false
null
Thing C SomeFlag = true
First you count all the items in things
. So you iterate over 4 objects, find 4 objects, and know that the result is 4. Easy.
Now you want to count all of the items in subset
which means you need to figure out which items are in subset
in the first place. So you go about counting them:
Thing A .... A.SomeFlag is true, so count it
Thing B .... B.SomeFlag is not true, so don't count it
null .... null.SomeFlag NULLREFERENCEEXCEPTION
And that's where your error comes from.
Note that even if all of the elements in things are not null, you can still get a NullReferenceException if the .SomeFlag
get accessor has a side effect that could cause a NullReferenceException.
Upvotes: 2
Reputation: 273169
An IEnumerable<Thing>
implies deferred execution.
In your first fragment subset
and things
are never enumerated.
In the second fragment, it is the call to Count()
that enumerates the lists and only then it comes to light that one of the a
is null in a => a.SomeFlag
.
Upvotes: 5
Reputation: 125610
You can see what really happens here with a bit simplified example.
Test
class:
public class Test
{
public int Value { get; set; }
}
And LINQ query on IEnumerable<Test>
:
IEnumerable<Test> source = new List<Test>() {
new Test { Value = 10 },
null,
new Test { Value = 20 }
};
IEnumerable<Test> filteredSource = source.Where(x => x.Value > 10);
// return false
Console.WriteLine(filteredSource == null);
// throws NullReferenceException
Console.WriteLine(filteredSource.Count());
Why does it happens? Because filteredSource == null
does not cause collection enumeration, so Where
predicate is not being fired on any source
collection element.
However, when you call Count()
on filteredSource
the predicate is being called on every item from source
collection, and when it comes to an item which is null
: null.Value > 10
throws the exception.
How to make it work? Extend the predicate with x != null
check:
IEnumerable<Test> filteredSource = source.Where(x => x != null && x.Value > 10);
Upvotes: 4