186

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?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Sachin Kainth
  • 45,256
  • 81
  • 201
  • 304
  • 186
    Instead of `YourCollection.FirstOrDefault()`, you could use `YourCollection.DefaultIfEmpty(YourDefault).First()` for example. – sloth Oct 19 '12 at 10:38
  • 8
    I've been looking for something like the above comment for quite a while, it helped immensely. This should be the accepted answer. – Brandon Jan 10 '14 at 16:28
  • The above comment is the best answer. – Tom Padilla May 19 '14 at 14:45
  • In my case @sloth answer did not work when the value returned is nullable and assigned to a non nullable. I used `MyCollection.Last().GetValueOrDefault(0)` for that. Otherwise @Jon Skeet answer below is IMO correct. – Jnr Apr 02 '19 at 07:12

14 Answers14

242

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...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 7
    I know the question asks for reference type but your solution doesn't work for when elements are value types like `int`. I much prefer the use of `DefaultIfEmpty`: `src.Where(filter).DefaultIfEmpty(defaultValue).First()`. Works for both value type and reference type. – KFL Feb 16 '18 at 21:41
  • 1
    @KFL: For non-nullable value types I'd probably use that too - but it's more long-winded for nullable cases. – Jon Skeet Feb 16 '18 at 21:43
  • Awesome control over return types when default is null .. :) – Sundara Prabu Feb 17 '18 at 09:53
  • "No. Or rather, it always returns the default value for the element type... " - This did it for me, actually.. as I also misundestood the meaning of the function name by assuming you could provide any default value when required – Jesus Campon Mar 13 '19 at 12:45
  • I really liked this approach, but I did change the "T alternate" with "Func alternate", and then "return alternate();" that way I don't generate the extra object unless I need to. Especially useful if the function is called many times in a row, the constructor is slow or the alternate instance of the type takes a lot of memory. –  Dec 26 '19 at 15:37
  • 1
    **Important note:** if you use `FirstOrDefault(predicate)`, `DefaultIfEmpty` from other answers and comments won't work. The final predicate is what nulls the list, so you need to use `??` like in this answer. – Andrew May 14 '22 at 04:48
  • I have wondered about this. Thanks for you answer. If it would not return null if not found for a reference (class object type) it would make FirstOrDefault() useless for me. This is great. I wish I had known this sooner! It would have things easier. – John Foll Jun 05 '23 at 19:03
86

You can use DefaultIfEmpty followed by First:

T customDefault = ...;
IEnumerable<T> mySequence = ...;
mySequence.DefaultIfEmpty(customDefault).First();
Vitamin C
  • 871
  • 6
  • 2
  • I love the idea of `DefaultIfEmpty` - it works with ALL APIs that need a default to be specified: `First()`, `Last()`, etc. As a user, you don't need to remember which APIs allow to specify default which don't. Very elegant! – KFL Feb 16 '18 at 21:45
  • This is very much the nest answer. – Jesse Williams Dec 23 '18 at 01:03
  • 1
    Unfortunately, this doesn't work if you want to use `.First(Func)` – Darkproduct Apr 27 '22 at 14:38
54

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().

Rawling
  • 49,248
  • 7
  • 89
  • 127
  • Your generic methods need `` in their names, but more serious is that `value == default(T)` doesn't work (because who knows if `T` can be compared for equality?) – AakashM Oct 19 '12 at 10:54
  • Thanks for pointing that out, @AakashM; I've actually tried this now and I think it should be OK (although I don't like the boxing for value types). – Rawling Oct 19 '12 at 10:57
  • 3
    @Rawling Use `EqualityComparer.Default.Equals(value, default(T))` to avoid the boxing and avoid an exception if value is `null` – Lukazoid May 02 '14 at 15:08
20

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.

RB.
  • 36,301
  • 12
  • 91
  • 131
9

.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://learn.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_

Deniz
  • 356
  • 1
  • 6
  • 12
  • It is true that v6 fixes this, but note that you may get 'Cannot translate' if you are running it against a database because LINQ can't translate your statement into a query that may return a default value. Use .AsEnumerable() before .FirstOrDefault("") to fix this. Most of the query still runs on the server but FirstOrDefault now runs locally and doesn't need to be translated. – BWhite Aug 04 '23 at 01:06
  • Yes but it's a LINQ to Entities issue. Many other linq queries can not be tranlated/interpreted to sql. – Deniz Aug 18 '23 at 07:03
  • That's interesting. I would have guessed that it would work fine with LINQ to Entities and only fail with LINQ to SQL. I can say that on the SQL side, FirstOrDefault() works and FirstOrDefault("") does not. And it was not clear to me from the error message why or how to fix it. It is true that "Many linq queries can not be translated to sql," but that didn't help me recognize or solve the problem. – BWhite Aug 18 '23 at 18:33
  • Here is a list of linq methods than can be translated: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-linq-methods-linq-to-entities But at Entity Framework side, they can vary by EF versions. For example earlier versions of EF support GroupBy some time, after a few version later it stopped supporting, then it started to support again. So there is not a direct answer to your question as i know. – Deniz Aug 19 '23 at 10:45
7

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)),
    };
Matas Vaitkevicius
  • 58,075
  • 31
  • 238
  • 265
  • 3
    Note that `DefaultIfEmpty` returns the default IF the collection is empty (has 0 items). If you use `First` WITH a matching expression like in your example and that condition doesn't find any item your return value will be empty. – OriolBG Mar 10 '17 at 12:17
  • Exactly, beware of this answer, it doesn't do what you think it does. I tried this on my project and got `null`. – Andrew May 14 '22 at 04:45
6

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;

Samuel Diogo
  • 689
  • 10
  • 13
5

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!

BurnWithLife
  • 364
  • 4
  • 11
  • 2
    The only difference between this answer and Vitamin C's answer is that this one uses `FirstOrDefault` instead of `First`. According to https://msdn.microsoft.com/en-us/library/bb340482.aspx, the recommended usage is `First` – Daniel Sep 09 '15 at 21:43
3

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

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Raj.A
  • 51
  • 2
2

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);
    }
}
harri
  • 556
  • 5
  • 17
2

This worked for us

int valueOrDefault = myList.Find(x => x.Id == 1)?.Value ?? -1;
Homer
  • 7,594
  • 14
  • 69
  • 109
1

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
    }
}
Prince Owusu
  • 31
  • 1
  • 4
0

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!

Aaron Gibson
  • 1,280
  • 1
  • 21
  • 36
-1

Use DefaultIfEmpty() instead of FirstOrDefault().

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137