IEnumerable для IReadOnlyCollection

У меня есть IEnumerable<Object> и нужно передать метод в качестве параметра, но этот метод принимает IReadOnlyCollection<Object>

Можно ли преобразовать IEnumerable<Object> в IReadOnlyCollection<Object>?

Ответ 1

Один из способов - создать список и вызвать AsReadOnly():

IReadOnlyCollection<Object> rdOnly = orig.ToList().AsReadOnly();

Это создает ReadOnlyCollection<object>, который реализует IReadOnlyCollection<Object>.

Примечание: Так как List<T> реализует IReadOnlyCollection<T>, вызов AsReadOnly() является необязательным. Хотя вы можете вызвать свой метод с результатом ToList(), я предпочитаю использовать AsReadOnly(), чтобы читатели моего кода увидели, что метод, который я вызываю, не намерен изменять мой список. Конечно, они могли бы узнать одно и то же, посмотрев подпись метода, который я вызываю, но это хорошо, чтобы быть явным.

Ответ 2

В качестве альтернативы ответу dasblinkenlight, чтобы предотвратить листинг вызывающего абонента Список <T> вместо выполнения orig.ToList().AsReadOnly(), может быть лучше:

ReadOnlyCollection<object> rdOnly = Array.AsReadOnly(orig.ToArray());

Это одно и то же число вызовов метода, но один принимает другой как параметр, а не вызывает возвращаемое значение.

Ответ 3

Поскольку другие ответы, по-видимому, направлены в сторону упаковки коллекций по-настоящему только для чтения, позвольте мне добавить это.

Я редко, если вообще когда-либо, видел ситуацию, когда вызывающая сторона настолько напугана, что метод IEnumerable<T> -taking мог бы злонамеренно попытаться привести этот IEnumerable<T> обратно к List или другому изменяемому типу и начать изменять его. Кий органной музыки и злой смех!

Нет. Если код, с которым вы работаете, даже удаленно разумен, то если он запрашивает тип, который имеет только функции чтения (IEnumerable<T>, IReadOnlyCollection<T>...), он будет только читать.

Используйте ToList() и покончите с этим.

В качестве примечания: если вы создаете метод, о котором идет речь, обычно лучше всего запрашивать не более IEnumerable<T>, что указывает на то, что вы "просто хотите, чтобы куча элементов читалась". Нужен ли вам его Count или нужно перечислить его несколько раз - это деталь реализации, и она, безусловно, подвержена изменениям. Если вам нужно многократное перечисление, просто сделайте это:

items = items as IReadOnlyCollection<T> ?? items.ToList(); // Avoid multiple enumeration

Это сохраняет ответственность, где он принадлежит (настолько локально, насколько это возможно) и сигнатуру метода чистым.

С другой стороны, при возврате нескольких элементов я предпочитаю возвращать IReadOnlyCollection<T>. Зачем? Цель состоит в том, чтобы дать звонящему то, что соответствует разумным ожиданиям - ни больше, ни меньше. Эти ожидания обычно заключаются в том, что коллекция материализована и что число Count известно - именно то, что обеспечивает IReadOnlyCollection<T> (а простой IEnumerable<T> - нет). Будучи не более конкретным, чем этот, наш контракт соответствует ожиданиям, и метод по-прежнему свободен для изменения базовой коллекции. (Напротив, если метод возвращает List<T>, меня интересует, в каком контексте я должен индексировать список и изменять его... и ответ обычно - "нет".)