Использование IReadOnlyCollection<T>
или IReadOnlyList<T>
в сигнатуре метода вместо IEnumerable<T>
имеет то преимущество, что делает явным то, что вам может потребоваться проверить счетчик перед итерацией или выполнить итерацию несколько раз по какой-либо другой причине.
Однако у них есть огромный недостаток, который вызовет проблемы, если вы попытаетесь изменить код для использования интерфейсов, например, чтобы сделать его более тестируемым и дружественным для динамического прокси.Ключевым моментом является то, что IList<T>
не наследуется от IReadOnlyList<T>
и аналогично для других коллекций и их соответствующих интерфейсов только для чтения.(Короче говоря, это потому, что .NET 4.5 хотел сохранить совместимость ABI с более ранними версиями. Но они даже не воспользовались возможностью изменить это в ядре .NET. )
Этоозначает, что если вы получаете IList<T>
из какой-либо части программы и хотите передать его другой части, которая ожидает IReadOnlyList<T>
, вы не сможете! Однако вы можете передать IList<T>
как IEnumerable<T>
.
В конце, IEnumerable<T>
- единственный интерфейс только для чтения, поддерживаемый всеми коллекциями .NET, включая все интерфейсы коллекций.,Любая другая альтернатива вернется, чтобы укусить вас, когда вы поймете, что вы отстранены от некоторых архитектурных решений.Поэтому я думаю, что это правильный тип для использования в сигнатурах функций, чтобы выразить, что вы просто хотите использовать коллекцию только для чтения.
(Обратите внимание, что вы всегда можете написать метод расширения IReadOnlyList<T> ToReadOnly<T>(this IList<T> list)
, который просто приводит к приведению, если базовый типподдерживает оба интерфейса, но вы должны добавлять его вручную везде при рефакторинге, где IEnumerable<T>
всегда совместимо.)
Как всегда, это не является абсолютным, если вы пишете большой объем базы данных, где случайныймногократное перечисление будет катастрофой, вы можете предпочесть другой компромисс.