Наилучшая практика:Как предоставить ICollection, доступный только для чтения

StackOverflow https://stackoverflow.com/questions/285323

  •  08-07-2019
  •  | 
  •  

Вопрос

У меня есть ICollection<T> вызванный foos в моем классе, который я хочу предоставить как доступный только для чтения (см. этот вопрос).Я вижу, что интерфейс определяет свойство .IsReadOnly, что кажется уместным...Мой вопрос заключается в следующем:как мне сделать очевидным для потребителя класса, что foos доступен только для чтения?

Я не хочу полагаться на то, что они не забудут сделать запрос .IsReadOnly прежде чем попробовать не реализованный метод, такой как .Add().В идеале я хотел бы разоблачить foos в качестве ReadOnlyCollection<T>, но это не реализует IList<T>.Должен ли я разоблачать foo с помощью метода, вызываемого, например, GetReadOnlyFooCollection а не через свойство?Если да, то не смутит ли это кого-то, кто затем ожидает ReadOnlyCollection<T>?

Это C # 2.0, поэтому методы расширения, такие как ToList() недоступны...

Это было полезно?

Решение

Кажется, я решил вернуть IEnumerable с клонированными объектами.

public IEnumerable<Foose> GetFooseList() {
   foreach(var foos in Collection) {
     yield return foos.Clone();
   }
}
  • требуется метод клонирования в Foos.

Это не допускает внесения изменений в коллекцию.Помните, что ReadOnlyCollection является "негерметичным", поскольку объекты внутри него могут быть изменены, как указано в ссылке в другом посте.

Другие советы

Вы можете сделать "foos" доступной для чтения коллекцией следующим образом:

ReadOnlyCollection<T> readOnlyCollection = foos.ToList<T>().AsReadOnly();

Затем вы можете предоставить его как свойство вашего класса.

Редактировать:

    class FooContainer
    {
        private ICollection<Foo> foos;
        public ReadOnlyCollection<Foo> ReadOnlyFoos { get { return foos.ToList<Foo>().AsReadOnly();} }

    }

Примечание:Вы должны помнить, что как только вы получите ReadOnlyFoos collection, она больше не будет "синхронизирована" с вашей foos ICollection.Посмотрите на тема, на которую вы ссылались.

С тех пор, как вопрос был написан, в .NET 4.0 добавлен интерфейс IReadOnlyCollection<T>; вероятно, было бы хорошо использовать это как объявленный тип возвращаемого значения.

Это, однако, оставляет открытым вопрос о том, какой тип instance возвращать. Один из подходов заключается в клонировании всех элементов в исходной коллекции. Другой вариант - всегда возвращать оболочку только для чтения. Третье - вернуть оригинальную коллекцию, если она реализует List<T>. Каждый подход будет лучшим в определенных контекстах, но будет не идеальным (или, возможно, совершенно ужасным) в других. К сожалению, Microsoft не предоставляет стандартных средств, с помощью которых можно задать два очень важных вопроса:

<Ол>
  • Обещаете ли вы всегда и навсегда содержать одни и те же предметы, как и сейчас?

  • Можете ли вы безопасно подвергаться воздействию кода, который не должен изменять ваше содержимое.

  • Какой стиль упаковки подходит, зависит от того, что клиентский код ожидает от того, что он получает. Некоторые сценарии, которых следует избегать:

    <Ол>
  • Был предоставлен объект типа, который клиент распознает как неизменяемый, но вместо того, чтобы быть возвращенным напрямую, он дублируется с использованием типа, который клиент не распознает как неизменяемый. Следовательно, клиент вынужден снова дублировать коллекцию.

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

  • Объект изменяемого типа, который не должен быть изменен, предоставляется клиентом (приведен к интерфейсу только для чтения). Затем он напрямую предоставляется другому клиенту, который определяет, что это изменчивый тип, и приступает к его изменению.

  • Ссылка на изменяемую коллекцию получена и инкапсулирована в оболочку только для чтения, а затем возвращается клиенту, которому нужен неизменяемый объект. Метод, который возвратил коллекцию, обещал, что она неизменна, и поэтому клиент отказался сделать свою собственную защитную копию. Затем клиент плохо подготовлен к тому, что коллекция может измениться.

  • На самом деле никаких & безопасных " курс действий, который может выполнить объект с коллекциями, которые он получает от одних клиентов и должен быть представлен другим. Всегда дублирование всего - во многих случаях самый безопасный способ действий, но это может легко привести к ситуациям, когда коллекция, которую не нужно дублировать вообще, заканчивается дублированием сотни или тысячи раз. Возвращение ссылок в полученном виде часто может быть наиболее эффективным подходом, но также может быть семантически опасным.

    Я бы хотел, чтобы Microsoft добавила стандартное средство, с помощью которого можно было бы задавать вышеуказанные вопросы для коллекций или, еще лучше, предлагать сделать неизменный снимок их текущего состояния. Неизменяемая коллекция может очень дешево вернуть неизменяемый снимок своего текущего состояния (просто вернуть себя), и даже некоторые изменяемые типы коллекций могут возвращать неизменяемый снимок по цене, значительно меньшей стоимости полного перечисления (например, T[][] может быть поддержано). двумя ICloneable массивами, один из которых содержит ссылки на разделяемые неизменяемые массивы из 256 элементов, а другой - ссылки на неразделимые изменяемые массивы из 256 элементов. Создание снимка списка потребует клонирования только внутренних массивов, содержащих элементы которые были изменены с момента последнего снимка - потенциально намного дешевле, чем клонирование всего списка. К сожалению, поскольку нет стандартного "!", создайте неизменный снимок & "интерфейс" [обратите внимание, что <=> не считается поскольку клон изменяемого списка будет изменчивым, в то время как можно сделать неизменный снимок, инкапсулируя изменяемый клонв оболочке, доступной только для чтения, это будет работать только для объектов, которые можно клонировать, и даже типы, которые не могут быть клонированы, должны поддерживать " изменяемый снимок " функция.]

    Я рекомендую вернуться использовать ReadOnlyCollection < T > для сценария напрямую. Это делает использование явным для вызывающего пользователя.

    Обычно я бы предложил использовать соответствующий интерфейс. Но, учитывая, что .NET Framework в настоящее время не имеет подходящей IReadOnlyCollection, вы должны использовать тип ReadOnlyCollection.

    Также вы должны знать об использовании ReadOnlyCollection, потому что он на самом деле не только для чтения: Неизменность и ReadOnlyCollection

    Иногда вы можете захотеть использовать интерфейс, возможно, потому что вы хотите смоделировать коллекцию во время модульного тестирования. Посетите мою запись в блоге , чтобы добавить собственный интерфейс в ReadonlyCollection с помощью адаптер.

    Обычно я возвращаю IEnumerable < T > .

    Как только вы сделаете коллекцию доступной только для чтения (таким образом, методы, такие как Add , Remove и Clear , больше не будут работать), осталось не так много, что коллекция поддерживает то, что перечислимое не имеет - просто Count и Contains , я считаю.

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

    вернуть T []:

    private ICollection<T> items;
    
    public T[] Items
    {
        get { return new List<T>(items).ToArray(); }
    }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top