omega
omega

Reputation: 43833

How to handle no matches case in List.First in c#?

In IEnumerable.First function, how do I handle the case if there are no matches? Currently it just crashes...

MySPListItem firstItem = itemCollection.First(item => !item.isFolder);
if (firstItem != null)
{
    TreeNode firstNode = GetNodeByListItem(my_treeview.Nodes, firstItem, ReportObject);
    if (firstNode != null)
    {
        ReportObject.log("Selecting the first PDF");
        selectPDF(my_treeview, firstNode, queryStr_param);
    }
}

Error Message:

Sequence contains no matching element
Stacktrace: at System.Linq.Enumerable.First[TSource](IEnumerable1 source, Func2 predicate)

Upvotes: 10

Views: 17314

Answers (6)

Jodrell
Jodrell

Reputation: 35696

Ok, If it is exceptional for there to be no first,

try
{
    var first = enumerable.First();
}
catch (InvalidOperationException)
{
    // Oops, that was exceptional.
}

If you anticipate that there may be no first in some valid situations,

var first = enumerable.FirstOrDefault();
if (first == default(someType)) // null for reference types.
{
    // Ok, I need to deal with that.
}

Upvotes: 29

Larry
Larry

Reputation: 18031

Replace First by FirstOrDefault :

MySPListItem firstItem = itemCollection.FirstOrDefault(item => !item.isFolder);

Upvotes: 3

Simon Belanger
Simon Belanger

Reputation: 14870

While you do a null check on the find, you don't in your predicate. The line

    foundItem = itemCollection.Find(item => item.item.ID == PDFID);

Might throw an exception it item is null (have you inserted an null item in the collection?) or item.item is null (are you sure it's always there?).

You could do:

foundItem = itemCollection.Find(item => item != null &&
                                        item.item != null && 
                                        item.item.ID == PDFID);

More chatty, but you won't get a NullReferenceException.

Edit Well you changed your question. Now you do First. The First method will throw an exception if nothing is found. Use FirstOrDefault instead which will return null for a class or the default value for a struct.

    foundItem = itemCollection.FirstOrDefault(item => item != null &&
                                              item.item != null && 
                                              item.item.ID == PDFID);

Upvotes: 7

Ian
Ian

Reputation: 34489

It shouldn't throw an exception, you need to handle the case where it returns default(T). You might be getting a NullReferenceException because you're not handling the case where it returns null. For example:

IEnumerable<Cars> cars = GetCars();
Car car = cars.Find(c => c.Model == "Astra");
if(car != null) 
{
   // You found a car!
}

If you were doing the same for a struct, you'd check for it's default instead. Ints for example would be a 0:

int[] ints = new int[] { 1, 4, 7 };
int myInt = ints.Find(i => i > 5);
if(myInt != 0) // 0 is default(int)
{
   // You found a number
}

Upvotes: 0

Darren
Darren

Reputation: 70718

Check if the result is null:

   if (result == null)
   {
      Console.WriteLine("Not found");
   }

There is a clear example demonstrating what to do if the item is found/not found here

Upvotes: 0

Golo Roden
Golo Roden

Reputation: 150614

Quoted from the MSDN website you linked to:

The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type T.

This describes the return value. Hence, when no match is found, the default value for type T is returned, which means null for reference types, and things such as 0, false & co. for value types.

So in your calling code, simply check for this default value, and you're fine :-). What you can not do is just use the value that is being returned, as this e.g. might result in a NullReferenceException, if you are using a reference type.

Upvotes: 2

Related Questions