Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

selecting a property from FirstOrDefault in case FirstOrDefault returns null

Tags:

c#

.net

linq

I want to make following statement:

var block = blocksById.FirstOrDefault(X => X.Value == tracResult.ID).Key

My question is how to deal with it more correctly in case I have FirstOrDefault null value. I just not feel that if statments the only solution that can be here...

like image 825
Night Walker Avatar asked Nov 13 '13 07:11

Night Walker


People also ask

Can FirstOrDefault return null?

The major difference between First and FirstOrDefault is that First() will throw an exception if there is no result data for the supplied criteria whereas FirstOrDefault() returns a default value (null) if there is no result data.

What is the default value returned by FirstOrDefault?

The default value for reference and nullable types is null . The FirstOrDefault method does not provide a way to specify a default value. If you want to specify a default value other than default(TSource) , use the DefaultIfEmpty<TSource>(IEnumerable<TSource>, TSource) method as described in the Example section.

What does FirstOrDefault mean in C#?

FirstOrDefault<TSource>(IEnumerable<TSource>): This method returns the first element of the given sequence or collection without any condition. Or returns the default value if the given collection or sequence does not contain any element.

Which of the following can be used to take the first matching element but returns null in case no matches found?

FirstOrDefault(); It returns first item if does not match query. It is better practice to check the NULL after query.


1 Answers

Since the introduction of the null conditional operators (?), it's as simple as:

var block = blocksById.FirstOrDefault(X => X.Value == tracResult.ID)?.Key;

Keep in mind that in this scenario, even if Value is an int, block will be of type Nullable<int>, and hence, can be null.

However if what you want to assign a default value if null is returned you can make use of null coalescing operator (??) is this way:

var block = blocksById.FirstOrDefault(X => X.Value == tracResult.ID)?.Key ?? 6;

Nevertheless, for more complex Select statements, the following is still valid...


Some time ago...

Split it in Where and Select:

var block = blocksById.Where(x => x.Value == tracResult.ID)
                      .Select(x => x.Key)
                      .FirstOrDefault();

That way you won't get a NullRefferenceException if the FirstOrDefault returns null.

Alternative you can give it a default value like this:

var block = blocksById.Where(x => x.Value == tracResult.ID)
                      .Select(x => x.Key)
                      .FirstOrDefault() ?? somedefaultvalue;

Or as @Silvermind stated for non nullable to nullable types (int's):

var block = blocksById.Where(x => x.Value == tracResult.ID)
                      .Select(x => (int?) x.Key)
                      .FirstOrDefault() ?? somedefaultvalue;

Update: some people seems to have doubts about this being a valid use case and argue that the check for null has to be done later on in the program.

While in a lot of circumstances this is the case, is doesn't always have to be true, or if it is, it might be more convenient this way.

Some examples:

//one liner, null check delegated (not my favorite): 
return SomeCalculatedValue(collection.Where(condition).Select(selection).FirstOrDefault());

//or a mapping (shown with default value):
var result = collection.Where(condition)
                       .Select(c => 
                           { 
                                Foo = c.Foo,
                                Bar = c.Bar
                           }).FirstOrDefault()) ?? new { Foo = "New", Bar = "Empty"};
like image 139
Stefan Avatar answered Sep 30 '22 16:09

Stefan