У меня есть IEnumerable<Object>
и нужно передать метод в качестве параметра, но этот метод принимает IReadOnlyCollection<Object>
Можно ли преобразовать IEnumerable<Object>
в IReadOnlyCollection<Object>
?
У меня есть IEnumerable<Object>
и нужно передать метод в качестве параметра, но этот метод принимает IReadOnlyCollection<Object>
Можно ли преобразовать IEnumerable<Object>
в IReadOnlyCollection<Object>
?
Один из способов - создать список и вызвать AsReadOnly()
:
IReadOnlyCollection<Object> rdOnly = orig.ToList().AsReadOnly();
Это создает ReadOnlyCollection<object>
, который реализует IReadOnlyCollection<Object>
.
Примечание: Так как List<T>
реализует IReadOnlyCollection<T>
, вызов AsReadOnly()
является необязательным. Хотя вы можете вызвать свой метод с результатом ToList()
, я предпочитаю использовать AsReadOnly()
, чтобы читатели моего кода увидели, что метод, который я вызываю, не намерен изменять мой список. Конечно, они могли бы узнать одно и то же, посмотрев подпись метода, который я вызываю, но это хорошо, чтобы быть явным.
В качестве альтернативы ответу dasblinkenlight, чтобы предотвратить листинг вызывающего абонента Список <T> вместо выполнения orig.ToList().AsReadOnly()
, может быть лучше:
ReadOnlyCollection<object> rdOnly = Array.AsReadOnly(orig.ToArray());
Это одно и то же число вызовов метода, но один принимает другой как параметр, а не вызывает возвращаемое значение.
Поскольку другие ответы, по-видимому, направлены в сторону упаковки коллекций по-настоящему только для чтения, позвольте мне добавить это.
Я редко, если вообще когда-либо, видел ситуацию, когда вызывающая сторона настолько напугана, что метод 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>
, меня интересует, в каком контексте я должен индексировать список и изменять его... и ответ обычно - "нет".)