Recommended way to check if a sequence is empty
A method returns a sequence, IEnumerable<T>
, and you now want to check if it is empty. How do you recommend doing that? I'm looking for both good readability and good performance.
The first and most obvious way is to check that the count is greater than zero:
if(sequence.Count() == 0)
Has decent readability, but terrible performance since开发者_运维百科 it has to actually go through the whole sequence.
A method that I sometimes use is the following:
if(!sequence.Any())
This doesn't (as far as I know) have to go through the whole sequence, but the readability is a bit backwards and awkward. (Reads a lot better if we are checking that the sequence is not empty though).
Another option is to use First
in a try-catch, like this:
try
{
sequence.First();
}
catch(InvalidOperationException)
{
// Do something
}
Not a very pretty solution, and probably slower too, since it is using exceptions and stuff. Could prevent that by using FirstOrDefault
of course, except you would have a big problem if the first item in the sequence actually was the default value ;)
So, any other ways to check if a sequence is empty? Which one do you usually use? Which one do you recommend to use?
Note: For optimal readability I would probably put one of the above snippets in an IsEmpty
extension method, but I am still curious since I would have to do something inside that method as well :p
I would use !sequence.Any()
, personally.
If you really need to, you could always write your own extension method:
public static bool IsEmpty<T>(this IEnumerable<T> source)
{
return !source.Any();
}
Then you can write:
if (sequence.IsEmpty())
You can create an Extension method, with this implementation.
public static bool IsEmpty<T>(this IEnumerable<T> items) {
using (var enumerator = items.GetEnumerator())
{
return !enumerator.MoveNext();
}
}
Well all these methods you're calling are LINQ extension methods, so it depends how the LINQ provider was implemented. If you want to know if a sequence is empty, either Count() == 0
or Any() == false
is appropriate. I prefer Any()
myself.
However, depending on what actual Type your sequence
is, you might not need to use a LINQ extension method. I.e. if it's an array you can call sequence.Length
. If it's a collection, you can use sequence.Count
.
I use this extension methods to detect if the sequence is null or does not have any item and alternatively to detect if the sequence does have at least one item, much like the string.IsNullOrEmpty()
method.
public static bool IsNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
if (source == null) {
return true;
}
return !source.Any();
}
public static bool IsNotNullOrEmpty<TSource>(this IEnumerable<TSource> source) {
return !source.IsNullOrEmpty();
}
.
.
.
if (!sequence.IsNullOrEmpty()) {
//Do Something with the sequence...
}
You said:
if(sequence.Count() == 0)
Has decent readability, but terrible performance since it has to actually go through the whole sequence.
Is that actually true? You are talking about dealing with an Interface, IEnumerable<T>
, and yet you are making assumptions regarding its implementation which may or may not be true. In fact, many of the custom collections I've written over the years keep a private variable that stores the current count internally, which means that returning .Count
is a trivial matter that does not require iterating the entire collection.
So with that said, unless you know that a specific implementation is poorly optimized for .Count
, I would use .Count
. Avoid premature optimization wherever possible, and stick with readability.
A method that I sometimes use is the following:
if(!sequence.Any())
❶ This doesn't (as far as I know) have to go through the whole sequence, ❷ but the readability is a bit backwards and awkward. (Reads a lot better if we are checking that the sequence is not empty though).
- According to Microsoft, Any does indeed not have to go through the whole sequence. Quoting from the section Remarks:
The enumeration of
source
is stopped as soon as the result can be determined.
This is particularly true when testing for the presence of elements in an
if-else
statement. Arguably, readability is best if one tests for the presence of elements in theif
statement, and the absence of elements in theelse
, thereby avoiding the use of the!
operator:if (sequence.Any()) { } else { }
Most would consider that more readable than:
if (!sequence.Any()) { } else { }
精彩评论