ICollection <T>не основан на индексе, но функция TakeWhile () существует - PullRequest
2 голосов
/ 05 марта 2012

Я пытаюсь заменить использование T[] или List<T> в качестве параметров функции и возвращаемых значений более подходящими типами, такими как IEnumerable<T>, ICollection<T> и IList<T>.

ICollection<T> Насколько я понимаю, предпочтительнее IList<T>, когда вам нужны только базовые / простые функции сбора (например, функции перечисления и подсчета), поскольку это обеспечивает это с наименьшим ограничением.Из прочтенного здесь одного из главных отличий, который я думал, было то, что ICollection<T> не требует, чтобы базовая коллекция была основана на индексе, где IList<T> делает?

При переключении моих List<T> ссылок мне нужнозаменить вызов List<T>.GetRange(), и я был очень удивлен, обнаружив метод расширения ICollection<T>.TakeWhile(), который имеет выбор, поддерживающий перегрузку на основе индекса ?! (ссылка msdn)

Я запутался, почему этот метод существует в ICollection, где нет индекса, основанного на этом интерфейсе?Я неправильно понял или как этот метод может работать, если базовая коллекция, например, Hashset или что-то еще?

Ответы [ 3 ]

2 голосов
/ 05 марта 2012

Индексация может быть выполнена без поддержки коллекции

int i = -1;

foreach(var item in collection)
{
   i++;
   // item is at index i;
}
2 голосов
/ 05 марта 2012

Этот метод, как и большинство LINQ, включен на IEnumerable<T>. Любые функции, которые просто передают индексатор потребителю (например, TakeWhile), должны только зацикливаться при увеличении счетчика. Некоторые API могут оптимизировать с помощью индексатора, и тогда они сами решают, делать это или просто использовать IEnumerable<T> и просто пропускать (и т. Д.) Ненужные данные.

Например:

int i = 0;
foreach(var item in source) {
    if(!predicate(i++, item)) break;
    yield return item;
}
0 голосов
/ 05 марта 2012

TakeWhile и другие методы расширения из класса System.Linq.Enumerable работают на всех типах, реализующих IEnumerable<T>. Все они перебирают коллекцию (используя оператор foreach) и выполняют соответствующие действия.

Вот реализация метода TakeWhile с некоторыми упрощениями:

private static IEnumerable<TSource> TakeWhile<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    foreach (TSource item in source)
    {
        if (!predicate(item))
        {
            break;
        }
        yield return item;
    }
}

Как видите, он просто перебирает коллекцию и оценивает предикат. Это верно почти для всех других методов LINQ. То же самое произойдет, когда вы используете любую другую коллекцию, например HashSet<T>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...