Подтвердить что ты не робот

Только для чтения "Accessor Access" в С#

У меня есть следующий класс:

class SampleClass
{
   private ArrayList mMyList;

   SampleClass()
   {
       // Initialize mMyList
   }

   public ArrayList MyList
   {
       get { return mMyList;}
   }
}

Я хочу, чтобы пользователи могли получать mMyList, поэтому я разоблачил "get" через свойство, но я не хочу, чтобы изменения, которые они вносили в объект (например, MyList.Add(новый класс());) чтобы вернуться в мой класс.

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

Возможно ли это?

4b9b3361

Ответ 1

С помощью ArrayList вы достаточно ограничены, потому что в BCL нет только обычного класса коллекций. Быстрое и грязное решение - вернуть тип IEnumerable.

   public IEnumerable MyList
   {
       get { return mMyList;}
   }

Это фактически не позволит кому-то отдать в ArrayList, но по умолчанию он не разрешит изменения

Вы можете вернуть эффективный список только для чтения, вызвав ArrayList.ReadOnly. Однако возвращаемый тип - это ArrayList, поэтому пользователь все равно сможет скомпилировать с .Add, но это приведет к ошибке выполнения.

Ответ 2

Используйте метод ArrayList.ReadOnly() для создания и возврата обертки только для чтения в списке. он не будет копировать список, а просто создаст обходную оболочку только для чтения. Чтобы получить проверку времени компиляции, вы, вероятно, захотите вернуть обертку только для чтения, как IEnumerable, как предлагает @Jared.

public IEnumerable MyList
{
     get { return ArrayList.ReadOnly(mMyList); }
}

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

Этот метод является операцией O (1).

Ссылка

Ответ 3

Просто для продолжения ответа JaredPar. По его словам, возвращение фактического поля поддержки не является полностью безопасным, так как пользователь все еще способен динамически отбрасывать IEnumerable обратно на ArrayList.

Я бы написал что-то вроде этого, чтобы не было никаких изменений в исходном списке:

public IEnumerable MyList
{
    get
    {
         foreach (object o in mMyList)
             yield return o;
    }
}

Тогда, опять же, я бы предположительно использовал общий список (IEnumerable<T>), чтобы быть полностью безопасным.

Ответ 4

Используйте ReadOnlyCollection.

return new ReadOnlyCollection<object>(mMyList).

Вы также можете сделать поле ReadOnlyCollection a, и оно автоматически отразит изменения в базовом списке. Это наиболее эффективное решение.

Если вы знаете, что mMyList содержит только один тип объекта (например, он не имеет ничего, кроме DateTimes) вы можете вернуть ReadOnlyCollection<DateTime> (или какой-либо другой тип) для дополнительной безопасности типа. Если вы используете С# 3, вы можете просто написать

return new ReadOnlyCollection<DateTime>(mMyList.OfType<DateTime>().ToArray())

Однако это не будет автоматически обновляться в базовом списке, а также менее эффективно (он скопирует весь список). Лучший вариант - сделать mMyList общим List<T> (например, a List<DateTime>)

Ответ 6

Вы должны обернуть возвращаемое значение в коллекции только для чтения.

Ответ 7

Доступно из .NET v2.0

    public ArrayList MyList { get; private set; }

Ответ 8

Просто сделайте свойство Sealed (или NotInheritable в VB.NET) и readonly, как это:

   public sealed readonly ArrayList MyList
   {
       get { return mMyList;}
   }

Также не забудьте сделать поле поддержки как только для чтения:

   private readonly ArrayList mMyList;

Но для инициализации значения mMyList вы должны инициализировать его ТОЛЬКО в конструкторе, как в этом примере:

public SampleClass()
{
   // Initialize mMyList
   mMyList = new ArrayList();
}