【问题标题】:IEnumerable to something that I can get a Count from?IEnumerable 到我可以从中获得计数的东西?
【发布时间】:2009-07-20 20:00:41
【问题描述】:

我有这个:

private IEnumerable _myList;

我需要对那个对象进行计数。我之前在数组中键入 _myList 并获取长度,但现在我们将同一段代码用于不同类型的对象。它仍然是一个 Collection 类型(它是一个强类型的 Subsonic Collection 对象),一切都很好,除了我们需要获取对象中的项目总数的位。

我尝试将它输入到 CollectionBase 以及许多其他类型,但没有任何方法可以让我得到 .Count 或 .Length 或类似的东西。

谁能指出我正确的方向?

编辑:我没有使用 3.5,我使用的是 2。所以,处理 Linq 的任何事情都行不通。很抱歉没有早点发布。

【问题讨论】:

    标签: c# collections ienumerable


    【解决方案1】:

    这实际上是IEnumerable 而不是IEnumerable<T>?如果是这样,LINQ 不会直接帮助您。 (您可以按照其他地方的建议使用 Cast<T>(),但这会相对较慢 - 特别是,它不会针对 IList/IList<T> 实现进行优化。)

    我建议你写:

    public static int Count(this IEnumerable sequence)
    {
        if (sequence == null)
        {
            throw new ArgumentNullException("sequence");
        }
    
        // Optimisation: won't optimise for collections which
        // implement ICollection<T> but not ICollection, admittedly.
        ICollection collection = sequence as ICollection;
        if (collection != null)
        {
            return collection.Count;
        }
    
        IEnumerator iterator = sequence.GetEnumerator();
        try
        {
            int count = 0;
            while (iterator.MoveNext())
            {
                // Don't bother accessing Current - that might box
                // a value, and we don't need it anyway
                count++;
            }
            return count;
        }
        finally
        {
            IDisposable disposable = iterator as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
    }
    

    【讨论】:

    • try/finally 块而不是“using”语句的任何原因?
    • 因为不是所有的 IEnumerator 都是 IDisposables,所以我敢打赌。
    • @Rytmis 完全正确。 IEnumerator 扩展了 IDisposable,但 IEnumerator 没有,因此您不能在 using 语句中使用它。有趣的事实:foreach 仅在 C# 1.2 中开始处理迭代器。在 C# 1.0 中它没有。尽管有 .NET 1.1,但我不知道 C# 1.1 规范。
    • 谢谢。编译器会立即看到这一点,但我没有... ;-)
    【解决方案2】:

    System.Linq.Enumerable.Count 扩展方法对类型化的IEnumerable&lt;T&gt; 执行此操作。 对于无类型的IEnumerable,请尝试制作自己的扩展:

        public static int Count(this IEnumerable source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
    
            ICollection collectionSource = source as ICollection;
            if (collectionSource != null)
            {
                return collectionSource.Count;
            }
    
            int num = 0;
            IEnumerator enumerator = source.GetEnumerator();
            //try-finally block to ensure Enumerator gets disposed if disposable
            try
            {
                while (enumerator.MoveNext())
                {
                    num++;
                }
            }
            finally
            {
                // check for disposal
                IDisposable disposableEnumerator = enumerator as IDisposable;
                if(disposableEnumerator != null)
                {
                    disposableEnumerator.Dispose();
                }
            }
            return num;
        }
    

    【讨论】:

    • 只需确保在 using 语句中包含 System.Linq 即可在 Intellisense 中使用它。
    • 他还需要重新定义为 IEnumerable 而不是 IEnumerable。
    • Count() 仅适用于 IEnumerable,不适用于 IEnumerable。
    • 不要忘记处理枚举器。 (那时你基本上得到了我的答案:)
    • 感谢乔恩,我没有使用任何不同的一次性名称来添加我在其中有发言权的错觉:)
    【解决方案3】:

    如果您使用的是 .NET 3.5,则可以使用 Enumerable.Count() 从任何 IEnumerable&lt;T&gt; 获取计数。

    不过,这不适用于非通用 IEnumerable - 它需要 IEnumerable&lt;T&gt;

    不过,这应该可以工作,因为 Subsonic 的集合类为您实现了适当的接口。您需要将您的定义从 IEnumerable 更改为 IEnumerable&lt;MyClass&gt;

    【讨论】:

    • 是的,为什么声明IEnumerable而不是IEnumerable&lt;T&gt;
    【解决方案4】:

    LINQ 提供了Count() 扩展方法。

    using System.Linq;
    

    ...

    var count = _myList.Count();
    

    【讨论】:

      【解决方案5】:

      您使用的类型是 IEnumerable,它没有 Count 属性。但通用等效项 IEnumerable(T) 具有 Count 属性。

      显而易见的解决方案是使用 IEnumerable(T),但如果你不能,你可以这样做:

      _myList.Cast<MyListItemType>().Count()
      

      强制转换是将 IEnumerable 转换为 IEnumerable(SomeType) 的简单方法,但显然不是获得计数性能的最佳方法。

      如果性能是一个因素,我只会遍历这些值以获取计数,除非您知道基础集合具有 Count 属性(请参阅 Jon Skeet 的回答...)。

      【讨论】:

        【解决方案6】:

        如果您包含 System.Linq 命名空间,IEnumerable&lt;T&gt; 有一个 Count() extension method 可用。您可以编写自己的扩展方法以在非通用版本上获取它。 请注意,此方法会将值类型装箱,因此如果这可能最终成为您的性能问题,请使用 Jon Skeet's solution。这更简单。

        public static int Count(this IEnumerable enumerable)
        {
            int count = 0;
            foreach(object item in enumerable)
            {
                count++;
            }
            return count;
        }
        

        【讨论】:

        • 如果它类似于 int[],则将序列中的所有内容都框起来。没有必要 - 请参阅我的答案以获得更繁琐但可能更有效的解决方案。
        【解决方案7】:

        打电话给.ToList()怎么样?

        【讨论】:

        • 复制原始列表(对于长序列,这将分配几个越来越大的内存块,每次都复制结果)。
        • 无需转换为列表来获取计数 - Enumerable.Count() 应该也可以工作。
        【解决方案8】:

        如果底层对象实现了 ICollection,那么您可以使用 .Count() 属性。

        【讨论】:

          【解决方案9】:

          我需要同样的,我创建了 IEnumerableList。原因是我不想在每次需要通过整个可枚举对象进行计数时进行评估,因为它是使用扩展方法 Count() 完成的。

          更多信息在这里:http://fknet.wordpress.com/2010/08/11/string-formatwith-extension/

          【讨论】:

            猜你喜欢
            • 2016-09-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-08
            • 1970-01-01
            • 2015-06-26
            • 1970-01-01
            • 2017-11-27
            相关资源
            最近更新 更多