Я потратил немало часов на размышления о предмете разоблачения членов списка. В подобном вопросе мой, Джон Скит дал отличный ответ. Пожалуйста, не стесняйтесь смотреть.
ReadOnlyCollection или IEnumerable для экспонирования коллекций участников?
Я обычно довольно параноидален для разоблачения списков, особенно если вы разрабатываете API.
Я всегда использовал IEnumerable для отображения списков, так как он вполне безопасен и дает такую гибкость. Позвольте мне привести пример здесь
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IEnumerable<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
Любой, кто кодов против IEnumerable, здесь совершенно безопасен. Если позже я решу использовать упорядоченный список или что-то еще, ни один из их кодов не сломается, и это все равно приятно. Недостатком этого является то, что IEnumerable можно отбросить в список за пределами этого класса.
По этой причине многие разработчики используют ReadOnlyCollection для раскрытия члена. Это вполне безопасно, поскольку он никогда не может быть возвращен в список. Для меня я предпочитаю IEnumerable, поскольку он обеспечивает большую гибкость, должен ли я когда-либо реализовать что-то отличное от списка.
Я придумал новую идею, которую мне больше нравится. Использование IReadOnlyCollection
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return new ReadOnlyCollection<WorkItem>(this.workItems);
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
Я чувствую, что это сохраняет некоторую гибкость IEnumerable и инкапсулируется довольно красиво.
Я разместил этот вопрос, чтобы внести свой вклад в мою идею. Вы предпочитаете это решение для IEnumerable? Как вы думаете, лучше использовать конкретное возвращаемое значение ReadOnlyCollection? Это довольно дискуссия, и я хочу попытаться выяснить, какие преимущества/недостатки мы все можем придумать.
Заранее благодарим за вход.
ИЗМЕНИТЬ
Прежде всего, спасибо всем вам за то, что вы так много способствовали обсуждению. Я, конечно, узнал тонну от каждого и хотел бы искренне поблагодарить вас.
Я добавляю несколько дополнительных сценариев и информации.
Есть некоторые распространенные ошибки с IReadOnlyCollection и IEnumerable.
Рассмотрим пример ниже:
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
Приведенный выше пример может быть возвращен в список и изменен, даже если интерфейс только для чтения. Интерфейс, несмотря на то, что тезка не гарантирует неизменность garuantee. Это зависит от вас, чтобы обеспечить непреложное решение, поэтому вы должны вернуть новый ReadOnlyCollection. Создавая новый список (копия по существу), состояние вашего объекта безопасно и звучит.
Richiban говорит, что это лучше всего в его комментарии: интерфейс гарантирует только то, что что-то может сделать, а не то, что он не может сделать
Ниже приведен пример.
public IEnumerable<WorkItem> WorkItems
{
get
{
return new List<WorkItem>(this.workItems);
}
}
Вышеупомянутые могут быть заброшены и мутированы, но ваш объект по-прежнему остается неизменным.
Другим вне оператора коробки будут классы коллекции. Рассмотрим следующее:
public class Bar : IEnumerable<string>
{
private List<string> foo;
public Bar()
{
this.foo = new List<string> { "123", "456" };
}
public IEnumerator<string> GetEnumerator()
{
return this.foo.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
В приведенном выше классе могут быть методы для мутирования foo так, как вы хотите, но ваш объект никогда не может быть передан в список любого рода и мутирован.
Carsten Führmann дает фантастический пример о операторах return return в IEnumerables.
Еще раз спасибо.