4thSpace
4thSpace

Reputation: 44352

Better way to check for elements in list?

If I want to perform actions such as .Where(...) or .Max(...), I need to make sure the list is not null and has a count greater than zero. Besides doing something such as the following everytime I want to use the list:

if(mylist != null && mylist.Count > 0)
{...}

is there something more inline or lambda like technique that I can use? Or another more compressed technique?

Upvotes: 8

Views: 1532

Answers (8)

Chris Shouts
Chris Shouts

Reputation: 5437

Use empty collections instead of null collections. Where will work just fine against an empty collection, so you don't need to ensure that Count > 0 before calling it. You can also call Max on an empty collection if you do a bit of gymnastics first.

For IEnumerable<T> use Enumerable.Empty<T>()

For T[] use new T[0]

For List<T> use new List<T>()

Upvotes: 2

Amy B
Amy B

Reputation: 110221

My general preference is to have empty list instances, instead of null list variables. However, not everyone can cajole their co-workers into this arrangment. You can protect yourself from null list variables using this extension method.

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source)
{
  return source ?? Enumerable.Empty<T>();
}

Called by:

Customers result = myList.EmptyIfNull().Where(c => c.Name == "Bob");

Most linq methods work on empty collections. Two methods that don't are Min and Max. Generally, I call these methods against an IGrouping. Most IGrouping implementations have at least one element (for example, IGroupings generated by GroupBy or ToLookup). For other cases, you can use Enumerable.DefaultIfEmpty.

int result = myList.EmptyIfNull().Select(c => c.FavoriteNumber).DefaultIfEmpty().Max();

Upvotes: 3

cwharris
cwharris

Reputation: 18125

Don't let the list be null

Ensure the object is always in a valid state. By ensuring the list is never null, you never have to check that the list is null.

public class MyClass
{
    private readonly IEnumerable<int> ints;

    public MyClass(IEnumerable<int> ints)
    {
        this.ints = ints;
    }

    public IEnumerable<int> IntsGreaterThan5()
    {
        return this.ints.Where(x => x > 5);
    }
}

Even if this list were empty, you'd still get a valid IEnumerable<int> back.

Max and Min overloads with Nullable types

That still doesn't solve the "Max" and "Min" problems though. There's an overload of Max and Min that take selectors. Those selector overloads can return nullable ints, so your max method becomes this:

this.ints.Max(x => new int?(x));

Therefore, you run Max and check to see if you've gotten a null value or an integer back. voila!

Other Options

Custom Extension Methods

You could also write your own extension methods.

public static MinMaxHelper()
{
    public static int? MaxOrDefault(IEnumerable<int> ints)
    {
        if(!ints.Any())
        {
            return null;
        }

        return ints.Max();
    }

    public static int MaxOrDefault(IEnumerable<int> ints, int defaultValue)
    {
        if(!ints.Any())
        {
            return defaultValue;
        }

        return ints.Max();
    }
}

Overriding Linq Extension Methods

And finally, remember that the build in Linq extension methods can be overriden with your own extension methods with matching signatures. Therefore, you could write an extension method to replace .Where(...) and .Max(...) to return null (or a default value) instead of throwing an ArgumentNullException if the Enumerable is null.

Upvotes: 2

fearofawhackplanet
fearofawhackplanet

Reputation: 53446

You don't need to check Count to call Where. Max needs a non-empty list for value types but that can be overcome with an inline cast, eg

int? max = new List<int>().Max(i => (int?)i); // max = null

Upvotes: 1

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112762

You can use ?? operator which converts null to the value you supply on the right side:

public ProcessList(IEnumerable<int> ints)
{
    this.ints = ints ?? new List<int>();
}

By the way: It is not a problem to process an empty list using LINQ.

Upvotes: 1

Muhammad Hasan Khan
Muhammad Hasan Khan

Reputation: 35146

public static class LinqExtensions
{
     public static bool IsNullOrEmpty<T>(this IEnumerable<T> items)
     {
           return items == null || !items.Any();
     }
}

You can then do something like

if (!myList.IsNullOrEmpty())
 ....

Upvotes: 9

Andy Rose
Andy Rose

Reputation: 17014

If there is a risk of your list being null you will alway have to check that before calling any of its methods but you could use the Any() method rather than count. This will return true as soon as it counts one item regardless if there is one or more item in the list. This saves iterating over the entire list which is what Count will do:

if(mylist != null && mylist.Any())
{...}

Upvotes: 1

Igor
Igor

Reputation: 34011

You could try myList.Any() instead of .Count, but you'd still need to check for null.

Upvotes: 1

Related Questions