Simplifying LINQ Query
I need a little help simplifying a LINQ query. Conditions are as follows:
- I need to apply
bool IsValid(string expression)
to every element of a given sequence.开发者_开发知识库 - If
IsValid
is true for all elements, returntrue
. - If
IsValid
is false for any element, returnfalse
. - If the sequence is null or empty, return
false
as well.
The query I came up with is
try
{
(sequence.DefaultIfEmpty().Where(item => !IsValid(item).Count() == 0)
}
catch (ArgumentNullException)
{
return false;
}
The point is that IsValid(null)
throws an ArgumentNullException
which is caught by the catch
block. However, I think this is too tricky. Is there any way I can simplify the method without relyinf on this fact?
why not:
return sequence.Any() && sequence.All(item => IsValid(item));
If you are worried about the separate sequence.Any()
check that results in a Resharper warning (which is warranted with any sequence that you can only iterate over once like a network, DB etc.) you could write a generic extension method that does the check and iterates the sequence only once:
public static bool NotEmptyAndValid<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
bool hasItem = false;
foreach(var item in source)
{
hasItem = true;
if(!predicate(item))
return false;
}
return hasItem;
}
Then you can just do:
return sequence.NotEmptyAndValid( x => IsValid(x));
You should be able to use:
return sequence.Any() && sequence.All(item => IsValid(item));
I'm not sure it's going to be easy to do this nicely with just a single pass. I'm sure it's doable, but I'm not sure it'd be nice. However, it's dead easy to write your own extension method:
(EDIT: I see BrokenGlass has now written a similar method with foreach
. I'll leave this as an alternative.)
public static boolean AllAndNotEmpty<T>(this IEnumerable<T> source,
Func<T, bool> predicate)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
if (predicate == null)
{
throw new ArgumentNullException("predicate");
}
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
return false;
}
do
{
if (!predicate(iterator.Current))
{
return false;
}
} while (iterator.MoveNext());
}
return true;
}
Then:
var result = items.AllAndNotEmpty(IsValid);
精彩评论