【问题标题】:Calculating Count for IEnumerable (Non Generic)计算 IEnumerable 的计数(非通用)
【发布时间】:2011-08-02 00:41:05
【问题描述】:

谁能帮我解决IEnumerableCount 扩展方法(非通用接口)。

我知道 LINQ 不支持,但是如何手动编写呢?

【问题讨论】:

    标签: c# .net linq extension-methods ienumerable


    【解决方案1】:

    我认为首先选择代表元素序列的类型应该是 ICollection 而不是 IEnumerable

    ICollectionICollection<T> 都提供了一个 Count 属性,而且每个 ICollection 都实现了 IEnumearable。

    【讨论】:

      【解决方案2】:

      最简单的形式是:

      public static int Count(this IEnumerable source)
      {
          int c = 0;
          using (var e = source.GetEnumerator())
          {
              while (e.MoveNext())
                  c++;
          }
          return c;
      }
      

      然后您可以通过查询ICollection 来改进这一点:

      public static int Count(this IEnumerable source)
      {
          var col = source as ICollection;
          if (col != null)
              return col.Count;
      
          int c = 0;
          using (var e = source.GetEnumerator())
          {
              while (e.MoveNext())
                  c++;
          }
          return c;
      }
      

      更新

      正如 Gerard 在 cmets 中指出的那样,非泛型 IEnumerable 不会继承 IDisposable,因此正常的 using 语句将不起作用。如果可能,尝试处理此类枚举器可能仍然很重要——迭代器方法实现了IEnumerable,因此可以间接传递给Count 方法。在内部,该迭代器方法将依赖于对Dispose 的调用来触发它自己的try/finallyusing 语句。

      为了在其他情况下也能轻松做到这一点,您可以制作自己的 using 语句版本,在编译时不那么繁琐:

      public static void DynamicUsing(object resource, Action action)
      {
          try
          {
              action();
          }
          finally
          {
              IDisposable d = resource as IDisposable;
              if (d != null)
                  d.Dispose();
          }
      }
      

      更新后的Count 方法将是:

      public static int Count(this IEnumerable source) 
      {
          var col = source as ICollection; 
          if (col != null)
              return col.Count; 
      
          int c = 0;
          var e = source.GetEnumerator();
          DynamicUsing(e, () =>
          {
              while (e.MoveNext())
                  c++;
          });
      
          return c;
      }
      

      【讨论】:

      • "查询 IList" - 或查询它的基本接口 ICollection
      • 我试用了这个扩展,using 给出了System.Collections.IEnumerable 的编译错误。我将代码更改为 Count<T>(this IEnumerable<T> source) 编译。
      【解决方案3】:

      不同类型的IEnumerable有不同的确定count的最优方法;不幸的是,没有通用的方法可以知道哪种方法最适合任何给定的 IEnumerable,甚至没有任何标准方法可以让 IEmumerable 指示以下哪种技术最好:

      1. 直接询问对象即可。支持 IEnumerable 的某些类型的对象,例如 Array、List 和 Collection,具有可以直接报告其中元素数量的属性。
      2. 枚举所有项,丢弃它们,并计算枚举项的数量。
      3. 将所有项目枚举到一个列表中,如果需要再次使用该枚举,则使用该列表。

      在不同的情况下,上面的每一个都是最优的。

      【讨论】:

        【解决方案4】:
        yourEnumerable.Cast<object>().Count()
        

        关于性能的评论:

        我认为这是过早优化的一个很好的例子,但是你去吧:

        static class EnumerableExtensions
        {
            public static int Count(this IEnumerable source)
            {
                int res = 0;
        
                foreach (var item in source)
                    res++;
        
                return res;
            }
        }
        

        【讨论】:

        • @Daniel 检查ICollection 的答案更好,因为它值得...
        • @Marc 第一个.Cast&lt;object&gt;().Count() 已经进行了检查(通用和非通用)。但是,是的,第二种解决方案可以通过检查来改进。
        • 将其转换为通用 IEnumerable 版本有什么意义?这将击败使用非通用 IEnumerable 背后的原因 - 正是因为您不知道/不关心元素类型。那么,您将无法对元素类型进行任何编译时转换,因为它们是未知的(如果它们是已知的 - 所使用的 IEnumerable 首先应该是通用的)。
        • 如果all最终需要的是获取元素总数的方法,也许对象类型不应该是IEnumerable而是ICollection。通用和非通用版本都提供了 Count 属性。
        • 我同意编辑答案中的“过早优化”论点。
        猜你喜欢
        • 2012-11-05
        • 1970-01-01
        • 1970-01-01
        • 2019-02-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-27
        相关资源
        最近更新 更多