Я лично использую ICollection<T>
для обычных свойств, просто потому, что это хорошо известный интерфейс с минимальными накладными расходами, т. Е. Создать ICollection
намного быстрее, чем IList
.Конечно, вы можете использовать HashSet<T>
, что и используется в EF Core, но я считаю, что HashSet
немного сложнее установить, чем ICollection<T>
, что занимает List<T>
.
Примечание: я не смотрел на скорость создания для любого из них - я просто делаю это, потому что книга "Руководство по проектированию фреймворка" демонстрирует это как лучший опыт - см. Стр. 250.
Единственное место, где вы должны использовать HashSet<T>
, если вы используете неинициализированные коллекции полей поддержки, например,
private HashSet<Review> _reviews;
public IEnumerable<Review> Reviews => _reviews?.ToList();
IEnumerable<T>
- это особый случай, потому что он превращает коллекцию в версию только для чтения, из-задо IEnumerable
без использования метода Add
или Remove
.Вспомогательные поля плюс IEnumerable<T>
(см. Код выше) позволяет вам "заблокировать" отношения коллекции, чтобы их можно было изменить только внутри класса (см. Мою статью Проектирование на основе домена в EF Core ).
Когда я использую вспомогательные коллекции полей, я оставляю их неинициализированными, поэтому они должны быть HashSet<T>
.Это позволяет мне определить, когда я забыл использовать .Include при загрузке объекта, например, если я загрузил книгу без .Include(p => p.Reviews)
и затем получил доступ к свойству Reviews, я получил бы исключение нулевой ссылки.Это просто безопасный способ программирования.
Если вы инициализируете коллекцию вспомогательных полей, то это может быть ICollection
и т. Д., Но я не рекомендую инициализировать коллекцию вспомогательных полей, потому что это может вызвать проблемы, если вызабудьте включить, а затем добавить элемент в коллекцию.В этом случае EF Core удаляет все существующие обзоры и заменяет их новыми, которые вы добавили.С точки зрения EF Core, он делает то, что вы сказали, но, скорее всего, НЕ то, что вы намеревались.