Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Enumerable.SequenceEqual throws exception if any parameter is null?

Tags:

c#

linq

I was trying to use Enumerable.SequenceEqual(x,y) as I expected it to work based on Object.Equals(x,y) method, which returns false if x or y is null, and true if both are null (for null cases).

However Enumerable.SequenceEqual(x,y) throws exception if any parameter is a null reference and will not return true if it is given two nulls.

In my code I check for collection equality quite often so I created a method that mimics Object.Equals behaviour for sequences but I just wonder whats the logic behind such default behaviour, and is there maybe an existing method with no exceptions on nulls?

like image 453
Valentin Kuzub Avatar asked Jun 20 '11 05:06

Valentin Kuzub


2 Answers

Well, the MSDN documentation explicitly states that it throws an ArgumentNullException in case any one of the passed in sequences is null. I assume it's to keep consistency with "standard behaviour" where an object throws a NullReferenceException when you try to dereference it. Consider this:

 List<int> foo = null;
 foo.SequenceEqual(new List<int>());

This would be ok as SequenceEqual is an extension method and therefore can handle a null object but it would also be confusing. Every extension method provided by Linq follows this behaviour as far as I know. Also you don't need to handle special null cases for every extension method (you would need to agree about sensible behaviour and add additional logic and maintain and test it). Saying that it is illegal makes it more robust (against logic bugs) and consistent from a framework perspective. I use Linq a lot and never ran into that problem - I just make sure all my sequences are not null. Reduces code clutter a lot (removes lots of null checks from the code).

like image 110
ChrisWue Avatar answered Sep 30 '22 01:09

ChrisWue


The point at which it is checking for sequence equality is not when that exception is being thrown. It is being thrown earlier as an argument validator. Consider the method:

public static bool SequenceEquals<T>(this IEnumerable<T> source, IEnumerable<T> target)
{
    // Stuff
}

We explicitly need to check that source and target are not null, because if any of them are, then we can't check for sequence equality. This is an unworkable state, and the result of SequenceEquals should be governed by the contents of the enumerables, not the state of the enumerables. If it were to include the latter, when returning false, how would the caller know whether it is actually failing because the sequences are not equal, or whether one or both of the enumerables are null?

If we didn't thrown an ArgumentNullException here, the CLR would thrown a NullReferenceException when you try and access one of the null enumerables. Simply saying Object reference not set to an instance of an object is a lot less helpful then The argument <something> cannot be null.

Remember, the type of exception thrown is typically one of the most helpful indicators about why an exception was thrown.

like image 24
Matthew Abbott Avatar answered Sep 30 '22 00:09

Matthew Abbott