是否通常(或鼓励)实践重载函数以接受IEnumerable <T>,ICollection <T>,IList <T>等?

Dan*_*Tao 1 .net c# ienumerable ilist overloading

编辑:

根据给出的答案,我已经明确地告诉我下面的设计应该如何实现.考虑到这些建议(并且回应一条礼貌地指出我的示例代码甚至没有编译的评论),我编辑了以下代码以反映普遍的共识似乎是什么.根据代码,剩下的问题可能已经不再有意义了,但我将其留给后代.


假设我有一个函数的三个重载,一个采取IEnumerable<T>,一个采取ICollection<T>,一个采取IList<T>,如下所示:

public static T GetMiddle<T>(IEnumerable<T> values) {
    IList<T> list = values as IList<T>;
    if (list != null) return GetMiddle(list);

    int count = GetCount<T>(values);

    T middle = default(T);
    int index = 0;

    foreach (T value in values) {
        if (index++ >= count / 2) {
            middle = value;
            break;
        }
    }

    return middle;
}

private static T GetMiddle<T>(IList<T> values) {
    int middleIndex = values.Count / 2;
    return values[middleIndex];
}

private static int GetCount<T>(IEnumerable<T> values) {
    // if values is actually an ICollection<T> (e.g., List<T>),
    // we can get the count quite cheaply
    ICollection<T> genericCollection = values as ICollection<T>;
    if (genericCollection != null) return genericCollection.Count;

    // same for ICollection (e.g., Queue<T>, Stack<T>)
    ICollection collection = values as ICollection;
    if (collection != null) return collection.Count;

    // otherwise, we've got to count values ourselves
    int count = 0;
    foreach (T value in values) count++;

    return count;
}
Run Code Online (Sandbox Code Playgroud)

这里的想法是,如果我有一个IList<T>,这使我的工作最容易; 另一方面,我仍然可以用一个ICollection<T>甚至一个IEnumerable<T>; 这些接口的实现效率不高.

我不确定这是否会起作用(如果运行时能够根据传递的参数选择重载),但我已经测试了它,它似乎.

我的问题是:我没有想到这种方法有问题吗?或者,这实际上是一个很好的方法,但有一种更好的方法来实现它(可能通过尝试将values参数转换为IList<T>第一个并在运行时运行更高效的重载)?我只是想知道别人的想法.

Tri*_*ian 5

如果您看一下如何使用Reflector实现LINQ扩展方法,您可以看到IEnumerable <T>上的一些扩展方法,例如Count(),尝试将序列强制转换为ICollection <T>或IList < T>优化操作(例如,使用ICollection <T> .Count属性而不是迭代IEnumerable <T>并计算元素).所以你最好的选择是最有可能接受IEnumerable <T>,然后在ICollection <T>或IList <T>可用的情况下进行这种优化.