8

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?

4thSpace
  • 43,672
  • 97
  • 296
  • 475
  • 5
    IMHO, objects like a list should never be null. I always initialize them if they're a class member, and if they're being returned from a function of my own creation, I make sure that function returns an empty list rather than null. – Dirk Dastardly Nov 09 '11 at 16:53
  • Possible duplicate of the answer at: http://stackoverflow.com/questions/41319/checking-if-a-list-is-empty-with-linq – S2S2 Nov 09 '11 at 16:58
  • You could always write your own extension methods to use the actions such as Where() or Max() that would include your null and Count test before using the actual extension method. – Paul Nov 09 '11 at 17:00
  • Drews answer, in conjunction with `myList.Max(x => new int?(x))`, will work for your needs. – cwharris Nov 09 '11 at 17:11

8 Answers8

9
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())
 ....
Muhammad Hasan Khan
  • 34,648
  • 16
  • 88
  • 131
  • What this condition does `!items.Any(); `? – sll Nov 09 '11 at 16:56
  • @sll, no, Any() will throw an ArgumentNullException if the source is null. – cwharris Nov 09 '11 at 17:19
  • @sll, I didn't understand your question. The `Any(...)` Linq Extension method will check to see if any of the items contained within the enumeration meet a condition. If no condition parameter is supplied, it will simply check to see if the enumeration contains any elements. `!items.Any()` is true if the list is empty, otherwise it is false. – cwharris Nov 11 '11 at 23:05
  • All thsi is clean for me, for me is not clear your first answer `Any() will throw an ArgumentNullException if the source is null.` In code below `items.Any()` never throw such exception because before we have condition `items == null` – sll Nov 11 '11 at 23:11
3

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();
Amy B
  • 108,202
  • 21
  • 135
  • 185
2

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.

cwharris
  • 17,835
  • 4
  • 44
  • 64
  • 2
    are you answering this question? – Snowbear Nov 09 '11 at 16:53
  • Sorry, I must have had a bad day. I've seen a lot of null-checking and list instantiation inside of while loops and such lately, instead of just instantiating the list with the class. – cwharris Dec 22 '11 at 00:26
2

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

Community
  • 1
  • 1
Chris Shouts
  • 5,377
  • 2
  • 29
  • 40
1

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

Igor
  • 33,276
  • 14
  • 79
  • 112
1

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())
{...}
Andy Rose
  • 16,770
  • 7
  • 43
  • 49
1

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.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
1

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
fearofawhackplanet
  • 52,166
  • 53
  • 160
  • 253