简化LINQ查询

问题描述:

我需要一些简化LINQ查询的帮助。条件如下:简化LINQ查询

  • 我需要将bool IsValid(string expression)应用于给定序列的每个元素。
  • 如果IsValid对所有元素均为true,则返回true
  • 如果IsValid对于任何元素均为false,则返回false
  • 如果序列为空或空,也返回false

我想出了查询

try 
{ 
    (sequence.DefaultIfEmpty().Where(item => !IsValid(item).Count() == 0) 
} 
catch (ArgumentNullException) 
{ 
    return false; 
} 

的一点是,IsValid(null)抛出一个ArgumentNullException这是由catch块捕获。但是,我认为这太棘手。没有任何方法可以简化方法而不依赖于这个事实?

为什么不:

return sequence.Any() && sequence.All(item => IsValid(item)); 

如果你担心单独sequence.Any()检查,结果在一个ReSharper的警告(这是必要的与你只能遍历一次像一个网络,数据库等任何序列)你可以写,做检查和迭代序列只有一次的通用扩展方法:

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; 
} 

然后,你可以这样做:

return sequence.NotEmptyAndValid(x => IsValid(x)); 
+0

是的,你是对的!但是,这引发了ReSharper的“可能的IEnumerable多重枚举”警告,我想避免这种警告。 – User

+0

DefaultIfEmpty将只返回一个空项目 - 这里的目的是什么? –

+0

是刚刚修复那部分,没有看到空集合的要求 – BrokenGlass

您应该能够使用:

return sequence.Any() && sequence.All(item => IsValid(item)); 
+0

是的,你是对的!但是,这引发了ReSharper的“可能的IEnumerable多重枚举”警告,我想避免这种警告。 – User

+0

@用户:在这种情况下,为了让您的空/空检查正常,循环可能是最好的选择... –

+0

看起来像一个同时回答给我。 –

我不知道它会很容易做到这一点很好只是一个单一的通行证。我相信这是可行,但我不确定它会不错。然而,它的死很容易编写自己的扩展方法:

(编辑:我明白了,BrokenGlass现在已经写了一个类似的方法与foreach我将离开这个作为一种替代)

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; 
} 

然后:

var result = items.AllAndNotEmpty(IsValid);