Konrad Viltersten
Konrad Viltersten

Reputation: 39058

Object reference not set to an instance while not being null

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

Answers (4)

p.s.w.g
p.s.w.g

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

JLRishe
JLRishe

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

Henk Holterman
Henk Holterman

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

MarcinJuraszek
MarcinJuraszek

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

Related Questions