FirstOrDefault: Default value other than null

.NetLinq

.Net Problem Overview


As I understand it, in Linq the method FirstOrDefault() can return a Default value of something other than null. What I haven't worked out is what kind of things other than null can be returned by this (and similar) method when there are no items in the query result. Is there any particular way that this can be set up so that if there is no value for a particular query some predefined value is returned as the default value?

.Net Solutions


Solution 1 - .Net

> As I understand it, in Linq the method FirstOrDefault() can return a Default value of something other than null.

No. Or rather, it always returns the default value for the element type... which is either a null reference, the null value of a nullable value type, or the natural "all zeroes" value for a non-nullable value type.

> Is there any particular way that this can be set up so that if there is no value for a particular query some predefined value is returned as the default value?

For reference types, you can just use:

var result = query.FirstOrDefault() ?? otherDefaultValue;

Of course this will also give you the "other default value" if the first value is present, but is a null reference...

Solution 2 - .Net

You can use DefaultIfEmpty followed by First:

T customDefault = ...;
IEnumerable<T> mySequence = ...;
mySequence.DefaultIfEmpty(customDefault).First();

Solution 3 - .Net

General case, not just for value types:

static class ExtensionsThatWillAppearOnEverything
{
    public static T IfDefaultGiveMe<T>(this T value, T alternate)
    {
        if (value.Equals(default(T))) return alternate;
        return value;
    }
}

var result = query.FirstOrDefault().IfDefaultGiveMe(otherDefaultValue);

Again, this can't really tell if there was anything in your sequence, or if the first value was the default.

If you care about this, you could do something like

static class ExtensionsThatWillAppearOnIEnumerables
{
    public static T FirstOr<T>(this IEnumerable<T> source, T alternate)
    {
        foreach(T t in source)
            return t;
        return alternate;
    }
}

and use as

var result = query.FirstOr(otherDefaultValue);

although as Mr. Steak points out this could be done just as well by .DefaultIfEmpty(...).First().

Solution 4 - .Net

From the documentation for FirstOrDefault

> [Returns] default(TSource) if source is empty;

From the documentation for default(T):

> the default keyword, which will return null for reference types and zero for numeric value types. For structs, it will return each member of the struct initialized to zero or null depending on whether they are value or reference types. For nullable value types, default returns a System.Nullable, which is initialized like any struct.

Therefore, the default value can be null or 0 depending on whether the type is a reference or value type, but you cannot control the default behaviour.

Solution 5 - .Net

Copied over from comment by @sloth

Instead of YourCollection.FirstOrDefault(), you could use YourCollection.DefaultIfEmpty(YourDefault).First() for example.

Example:

var viewModel = new CustomerDetailsViewModel
    {
            MainResidenceAddressSection = (MainResidenceAddressSection)addresses.DefaultIfEmpty(new MainResidenceAddressSection()).FirstOrDefault( o => o is MainResidenceAddressSection),
            RiskAddressSection = addresses.DefaultIfEmpty(new RiskAddressSection()).FirstOrDefault(o => !(o is MainResidenceAddressSection)),
    };

Solution 6 - .Net

You can also do this

	Band[] objects = { new Band { Name = "Iron Maiden" } };
	first = objects.Where(o => o.Name == "Slayer")
		.DefaultIfEmpty(new Band { Name = "Black Sabbath" })
		.FirstOrDefault();   // returns "Black Sabbath" 

This uses only linq - yipee!

Solution 7 - .Net

Actually, I use two approaches to avoid NullReferenceException when I'm working with collections:

public class Foo
{
	public string Bar{get; set;}
}
void Main()
{
	var list = new List<Foo>();
	//before C# 6.0
	string barCSharp5 = list.DefaultIfEmpty(new Foo()).FirstOrDefault().Bar;
	//C# 6.0 or later
	var barCSharp6 = list.FirstOrDefault()?.Bar;
}

##For C# 6.0 or later: Use ?. or ?[ to test if is null before perform a member access Null-conditional Operators documentation

Example: var barCSharp6 = list.FirstOrDefault()?.Bar;

##C# older version: Use DefaultIfEmpty() to retrieve a default value if the sequence is empty.MSDN Documentation

Example: string barCSharp5 = list.DefaultIfEmpty(new Foo()).FirstOrDefault().Bar;

Solution 8 - .Net

Instead of YourCollection.FirstOrDefault(), you could use YourCollection.DefaultIfEmpty(YourDefault).First() for example.

Solution 9 - .Net

.NET6 / c#10 Solution

.NET6 / c#10 solves this issue by adding new features to *OrDefault LINQ methods. New overloads let you specify a default value to use if the sequence is empty.

public static TSource FirstOrDefault<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate, TSource defaultValue);

Returns the first element of the sequence that satisfies a condition, or a specified default value if no such element is found.

Here's an example;

var nums = new List<int> { 1, 2, 3 };
var target = 4;

var value = nums.FirstOrDefault(x => x == target, -1); // value becomes -1.

Source: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.firstordefault?view=net-6.0#System_Linq_Enumerable_FirstOrDefault__1_System_Collections_Generic_IEnumerable___0____0_

Solution 10 - .Net

I just had a similar situation and was looking for a solution that allows me to return an alternative default value without taking care of it at the caller side every time I need it. What we usually do in case Linq does not support what we want, is to write a new extension that takes care of it. That´s what I did. Here is what I came up with (not tested though):

public static class EnumerableExtensions
{
    public static T FirstOrDefault<T>(this IEnumerable<T> items, T defaultValue)
    {
        foreach (var item in items)
        {
            return item;
        }
        return defaultValue;
    }

    public static T FirstOrDefault<T>(this IEnumerable<T> items, Func<T, bool> predicate, T defaultValue)
    {
        return items.Where(predicate).FirstOrDefault(defaultValue);
    }
        
    public static T LastOrDefault<T>(this IEnumerable<T> items, T defaultValue)
    {
        return items.Reverse().FirstOrDefault(defaultValue);
    }

    public static T LastOrDefault<T>(this IEnumerable<T> items, Func<T, bool> predicate, T defaultValue)
    {
        return items.Where(predicate).LastOrDefault(defaultValue);
    }
}

Solution 11 - .Net

This worked for us

int valueOrDefault = myList.Find(x => x.Id == 1)?.Value ?? -1;

Solution 12 - .Net

I know its been a while but Ill add to this, based on the most popular answer but with a little extension Id like to share the below:

static class ExtensionsThatWillAppearOnIEnumerables
{
    public static T FirstOr<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> alternate)
    {
        var thing = source.FirstOrDefault(predicate);
        if (thing != null)
            return thing;
        return alternate();
    }
}

This allows me to call it inline as such with my own example I was having issues with:

_controlDataResolvers.FirstOr(x => x.AppliesTo(item.Key), () => newDefaultResolver()).GetDataAsync(conn, item.ToList())

So for me I just wanted a default resolver to be used inline, I can do my usual check and then pass in a function so a class isn't instantiated even if unused, its a function to execute when required instead!

Solution 13 - .Net

If the list of items is not a nullable type consider casting to a nullable type then firstordefault and null coalescing operator with what ever default value you want.

Example:

static class MyClass
{
    public enum Level { Low, Medium, High }

    public static void Dosomething()
    {
        var levels = Enum.GetValues<Level>();

        var myLevel = levels.Select(x => (Level?)x).FirstOrDefault() ?? Level.Medium; // The Default value other than null
    }
}

Solution 14 - .Net

Use DefaultIfEmpty() instead of FirstOrDefault().

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSachin KainthView Question on Stackoverflow
Solution 1 - .NetJon SkeetView Answer on Stackoverflow
Solution 2 - .NetVitamin CView Answer on Stackoverflow
Solution 3 - .NetRawlingView Answer on Stackoverflow
Solution 4 - .NetRB.View Answer on Stackoverflow
Solution 5 - .NetMatas VaitkeviciusView Answer on Stackoverflow
Solution 6 - .NetBurnWithLifeView Answer on Stackoverflow
Solution 7 - .NetSamuel DiogoView Answer on Stackoverflow
Solution 8 - .NetRaj.AView Answer on Stackoverflow
Solution 9 - .NetDenizView Answer on Stackoverflow
Solution 10 - .NetharriView Answer on Stackoverflow
Solution 11 - .NetHomerView Answer on Stackoverflow
Solution 12 - .NetAaron GibsonView Answer on Stackoverflow
Solution 13 - .NetPrince OwusuView Answer on Stackoverflow
Solution 14 - .NetAbhishek SinghView Answer on Stackoverflow