Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FirstOrDefault() result of a struct collection?

So I've got a collection of structs (it's actually a WCF datacontract but I'm presuming this has no bearing here).

List<OptionalExtra> OptionalExtras; 

OptionalExtra is a struct.

public partial struct OptionalExtra 

Now I'm running the below statement:

OptionalExtra multiOptExtra = OptionalExtras.Where(w => w.Code == optExtra.Code).FirstOrDefault(); if (multiOptExtra != null) {  } 

Now this won't compile:

the operator != cannot be applied to opperands of type OptionalExtra and '<null>'

After a little googling I realised it's because OptionalExtra is a struct. Which I believe is not nullable unless defined as a nullable type?

So my question is, if my where statement returns no results what will be the outcome of the FirstOrDefault call? Will it thrown an exception?

Incidently this should never happen but better safe than sorry.

like image 317
Liam Avatar asked Mar 14 '13 10:03

Liam


People also ask

What is FirstOrDefault return in C#?

FirstOrDefault<TSource>(IEnumerable<TSource>, TSource) Returns the first element of a sequence, or a specified default value if the sequence contains no elements.

What does FirstOrDefault return if empty?

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 use of FirstOrDefault in MVC?

FirstOrDefault. It returns first specific element from a collection of elements if one or more than one match found for that element. A default value is returned, if no match is found for that element in the collection.

Should I use FirstOrDefault first?

Use First() when you are sure that a query must return a record, and use FirstOrDefault() when you are not sure whether it will return a record or not.


2 Answers

If your collection is empty, FirstOrDefault will return default(OptionalExtras). The default value of a struct is the struct with all its values in turn default initialized (i.e. zero, null, etc.).

If you assume that there will be an element and your code doesn't work with an empty collection, Use First() instead, since that will throw an exception when your collection is empty. It's generally better to fail fast than to return wrong data.

If you cannot assume that there will be an element, but also cannot deal with struct default initialization, you might make the structs in the collection a nullable value type, for example as follows:

OptionalExtras     .Where(w => w.Code == optExtra.Code)     .Cast<OptionalExtra?>()     .FirstOrDefault(); 

This way you can get a null return even for a struct. The key idea here is to extend the set of possible values to include something other than an OptionalExtra to allow detection of an empty list. If you don't like nullables, you could instead use a Maybe<> implementation (not a .NET builtin), or use an empty-or-singleton list (e.g. .Take(1).ToArray(). However, a nullable struct is likely your best bet.

TL;DR;

  • .FirstOrDefault<T>() returns default(T) if the sequence is empty
  • Use .First() instead if you assume the list is non-empty.
  • Cast to nullable and then use .FirstOrDefault<T>() when you cannot assume the list is non-empty.
like image 133
Eamon Nerbonne Avatar answered Oct 01 '22 06:10

Eamon Nerbonne


As others have said, the result of your code when no elements match will be:

default( OptionalExtra ) 

If you want a null returned, you can cast your list to OptionalExtra?

OptionalExtra? multiOptExtra = OptionalExtras.Cast<OptionalExtra?>().Where( ... 

You can then test for null

like image 30
Nick Butler Avatar answered Oct 01 '22 06:10

Nick Butler