Вернуть 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).

Пытаться

return new ReadOnlyCollection<Abc> (list);

На мой взгляд, лучший способ сделать это, чтобы вернуться 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> который предназначен только для чтения итератора и предоставляет методы для добавления и удаления элементов.

Другие вопросы по тегам