如何在 IEnumerable<T> 上实现 ICollection<T>

How to implement ICollection<T> on an IEnumerable<T>

我想知道如何根据 Microsoft 在 MSDN guidelines for collections 中的建议进行编程,其中说明如下:

AVOID using ICollection<T> or ICollection as a parameter just to access the
Count property. Instead, consider using IEnumerable<T> or IEnumerable and
dynamically checking whether the object implements ICollection<T> or ICollection.

简而言之,如何在 IEnumerable 上实现 ICollection?微软在那篇文章中有 link,但没有 "And here is how you do this" link.

这是我的场景。我有一个带有网格的 MVC 网络应用程序,可以对某些集合进行分页和排序。例如,在员工管理屏幕上,我在网格中显示员工列表。

最初我将集合作为 IEnumerable 返回。当我不需要分页时,这很方便。但现在我面临着分页,需要提取员工记录计数才能做到这一点。一种 解决方法 是通过 ref 将 employeeCount 整数传递给我的 getEmployeeRecords() 方法并在该方法中分配值,但这太麻烦了。

根据我在 Whosebug 上看到的内容,一般建议使用 IEnumerable 而不是 ICollection、Collection、IList 或 List。所以我不想就那个话题展开对话。 我只想知道如何使 IEnumerable 实现 ICollection,并提取记录计数, 因此我的代码更符合 Microsoft 的建议。证明这一点的代码示例或清晰的文章会有所帮助。

感谢您的帮助!

IEnumerable是接口,ICollection也是。它是实现一个或另一个或两者的对象的类型。您可以使用 obj is ICollection.

检查对象是否实现了 ICollection

示例:

public class MyCollection<T> : IEnumerable<T>, ICollection<T>
{
    // ... Implemented methods
}

// ...

void Foo(IEnumerable<int> elements)
{
    int count;
    if (elements is ICollection<int>) {
        count = ((ICollection<int>)elements).Count;
    }
    else {
        // Use Linq to traverse the whole enumerable; less efficient, but correct
        count = elements.Count();
    }
}

// ...

MyCollection<int> myStuff;
Foo(myStuff);

ICollection 不是已经实施 IEnumerable 了吗?如果你需要 collection 那么你需要 collection.

需要注意的一件事是,如果您使用 LINQ 的 Count() 方法,它已经为您进行了类型检查:

public static int Count<TSource>(this IEnumerable<TSource> source)
{
    if (source == null) throw Error.ArgumentNull("source");

    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;

    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;

    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator())
    {
        checked
        {
            while (e.MoveNext()) count++;
        }
    }

    return count;
}

Initially I returned the collection as IEnumerable.

好吧,你的问题已经解决了一半。 Return 类型应尽可能明确。如果您有一个集合,请将 return 类型设为该集合。 (我忘了在哪里,但是指南中提到了这一点。)

Based on what I've seen here on Whosebug, the general recommendation is to use IEnumerable instead of ICollection, or Collection, or IList, or List.

一些开发人员痴迷于将所有内容都转换为 IEnumerable。我不知道为什么,因为微软没有任何指导说这是个好主意。 (我确实知道有些人认为它以某种方式使 return 值不可变,但实际上任何人都可以将其转换回基本类型并对其进行更改。或者只是使用 dynamic 甚至都不会注意到你给了它们是一个 IEnumerable。)

这是 return 类型和局部变量的规则。对于参数你应该尽可能接受。实际上,这意味着接受 IEnumerable 或 IList,具体取决于您是否需要通过索引访问它。

AVOID using ICollection or ICollection as a parameter just to access the Count property.

这样做的原因是,如果您需要计数,您可能还需要通过索引访问它。如果不是今天,那么明天。所以继续使用 IList 以防万一。

(我不确定我是否同意,但确实有一定道理。)

In short, how do I implement ICollection on an IEnumerable?

简答:.Count() 扩展方法。确保导入 System.Linq.

长答案:

int count = 0;
if (x is ICollection)
    count = ((ICollection)x).Count;
else
    foreach (var c in x)
       count ++;