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...
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.
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.
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.
FirstOrDefault(); It returns first item if does not match query. It is better practice to check the NULL after query.
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...
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"};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With