Вернуть ReadOnlyCollection из IList<>
Итак, List<> содержит AsReadOnly(), который предоставляет вам коллекцию ReadOnlyCollection. Мне нужно иметь поле типа IList и свойство, которое возвращало бы коллекцию ReadOnlyCollection для этого списка.
Пример класса:
class Test
{
private IList<Abc> list;
public AddToList(Abc someItem) { /* adds inside the list */... }
public ReadOnlyCollection<Abc> List { get { return ??? } } // <- no "set" here!
}
Сценарий следующий: мне нужно иметь некоторую настраиваемую логику внутри моего класса, когда элемент добавляется в список, и я хочу ограничить добавление в этот список, вызывая AddToList(someitem), но не разрешая использование list.Add(someItem). Проблема в том, что я использую NHibernate, который требует интерфейса IList, поэтому я не могу привести / вызвать AsReadOnly() для IList (он не содержит этот метод).
Каким образом вы бы порекомендовали решить эту ситуацию? Мне просто нужно, чтобы NHibernate каким-то образом установил нужную коллекцию, но мне также нужно ограничить пользователей.
5 ответов
Вы можете просто подражать AsReadOnly()
:
public ReadOnlyCollection<Abc> List
{
get { return new ReadOnlyCollection<Abc>(list); }
}
ОБНОВЛЕНИЕ:
Это не создает копию list
, ReadOnlyCollection
не копирует данные, он работает непосредственно с предоставленным списком. Смотрите документацию:
Коллекция, доступная только для чтения, - это просто коллекция с оболочкой, которая предотвращает изменение коллекции; поэтому, если изменения сделаны в основной коллекции, коллекция только для чтения отражает эти изменения.
Этот конструктор является операцией O(1).
На мой взгляд, лучший способ сделать это, чтобы вернуться IEnumerable<Abc>
используя метод, предложенный Джоном Скитом:
public IEnumerable<Abc> Abcs {
get { return list.Skip(0); }
}
Если вы не беспокоитесь о том, что потребители IEnumerable<T>
вернуться к IList<T>
ты можешь просто вернуться IEnumerable<T>
,
ReadOnlyCollection<T>
имеет некоторые серьезные недостатки, основным из которых является то, что он реализует IList<T>
так что у него есть методы Add и Remove. Это может привести к ошибкам во время выполнения, если потребители не будут проверять его свойство ReadOnly. Я настоятельно рекомендую не использовать его.
Используйте следующий способ,
public class Test
{
private IList<SubTest> _subTests;
public virtual void AddSubTest(SubTest SubTest)
{
if (_subTests == null)
_subTests = new List<SubTest>();
_subTests.Add(SubTest);
return this;
}
public virtual IReadOnlyList<SubTest> SubTests
{
get
{
if (_subTests == null)
_subTests = new List<SubTest>();
return _subTests.AsReadOnly();
}
}
public void RemoveSubTest( SubTest SubTest )
{
if( _subTests == null )
return;
_subTests.Remove( SubTest );
}
}
используйте следующее отображение, и оно установит значение в поле, а не в свойство, доступное только для чтения.
<bag
name="SubTests" table="SubTest" lazy="true" access="field.camelcase-underscore"
optimistic-lock="false"
>
<key column ="TestID" />
<many-to-many class="SubTest, Domain" column="SubTestID" />
</bag>
Вы также можете вернуться IEnumerable<Abc>
который предназначен только для чтения итератора и предоставляет методы для добавления и удаления элементов.