2013-08-03 20 views
0

所以通常如果你想简单地检查一下IEnumerable<T>是否有任何项目,你会使用.Any()而不是.count > 0--尤其是当你打击像LINQ-to-Entities和.count可能会有一个沉重的表现惩罚。检查任意枚举是否有没有没有泛型的项目

我的问题是,我正在写一个IValueConverter取决于可枚举是否有项目或不改变的对象可见性:

public class CollectionEmptyVisibilityConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, string language) 
    { 
     var col = value as ICollection; 

     if (col == null) { return Visibility.Collapsed.ToString(); } 

     return (col.Count > 0) ? Visibility.Visible.ToString() : Visibility.Collapsed.ToString(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, string language) 
    { 
     throw new NotImplementedException(); 
    } 
} 

所以在这种情况下,我无法使用正常的扩展方法在IEnumerable<T>,因为我目前不能有<T>。我目前的实施限制了我实现ICollection的事情,这可能并不总是令人满意的。

我该如何以更高效的方式做到这一点?裸体IEnumerable(无框<T>)没有.Any()

回答

3

这会工作得很好:

public static class ExtensionMethods 
{ 
    public static bool Any(this IEnumerable t) { 
     foreach (var o in t) 
      return true; 
     return false; 
    } 
} 

基准:

public static class ExtensionMethods 
{ 
    public static bool AnyJR(this IEnumerable t) 
    { 
     foreach (var o in t) 
      return true; 
     return false; 
    } 

    public static bool AnyPhonicUK(this IEnumerable t) 
    { 
     var e = t.GetEnumerator(); 
     try { 
      return e.MoveNext(); 
     } 
     finally { 
      var edisp = e as IDisposable; 
      if (edisp != null) 
       edisp.Dispose(); 
     } 
    } 
} 

class Program 
{ 
    static long Test_AnyJR(List<int> l, int n) 
    { 
     var sw = Stopwatch.StartNew(); 

     for (int i = 0; i < n; i++) { 
      bool any = l.AnyJR(); 
     } 

     sw.Stop(); 
     return sw.ElapsedMilliseconds; 
    } 

    static long Test_AnyPhonicUK(List<int> l, int n) 
    { 
     var sw = Stopwatch.StartNew(); 

     for (int i = 0; i < n; i++) { 
      bool any = l.AnyPhonicUK(); 
     } 

     sw.Stop(); 
     return sw.ElapsedMilliseconds; 
    } 

    static void Main(string[] args) 
    { 
     var list = new List<int> { 1, 2, 3, 4 }; 

     int N = 10000000; 
     Console.WriteLine("{0} iterations using AnyJR took {1} ms.", N, Test_AnyJR(list, N)); 
     Console.WriteLine("{0} iterations using AnyPhonicUK took {1} ms.", N, Test_AnyPhonicUK(list, N)); 

     Console.ReadLine(); 
    } 
} 

结果:

10000000 iterations using AnyJR took 484 ms. 
10000000 iterations using AnyPhonicUK took 393 ms. 
+0

就问后,我结束了'col.GetEnumerator()调用MoveNext()'该作品,以及 - 问题的存在会更加快捷。?授予这两个文本中的一个非常接近的电话。在任何情况下都将标记为正确。 – PhonicUK

+1

@PhonicUK由于枚举器实现了'IDisposable',所以你不应该这样做。你可以将它封装在一个使用中,并返回'MoveNext()'以确保它被丢弃。 –

+0

@TimS。我很困惑 - “IEnumerator”不是“IDisposable”。 –

0
public object Convert(object value, Type targetType, object parameter, string language) 
{ 
    var col = value as ICollection; 
    if (col != null) 
     return col.Count > 0 ? Visibility.Visible : Visibility.Collapsed; 
    var enu = (IEnumerable)value; 
    foreach (var obj in enu) 
     return true; 
    return false; 
} 

或者(更简洁的,但可能是一个头发更慢):

public object Convert(object value, Type targetType, object parameter, string language) 
{ 
    var enu = (IEnumerable)value; 
    return enu.Cast<object>().Any() ? Visibility.Visible : Visibility.Collapsed; 
}