开发者

Simplifying LINQ Query

开发者 https://www.devze.com 2023-04-03 15:25 出处:网络
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.开发者_开发知识库

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, return true.
  • If IsValid is false for any element, return false.
  • 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);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号