"Только для чтения" доступ к свойствам в C#

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

class SampleClass
{
   private ArrayList mMyList;

   SampleClass()
   {
       // Initialize mMyList
   }

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

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

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

это возможно?

8 ответов


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

   public IEnumerable MyList
   {
       get { return mMyList;}
   }

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

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


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

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

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

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

ссылка


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

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

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

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


использовать ReadOnlyCollection.

return new ReadOnlyCollection<object>(mMyList).

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

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

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

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



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


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

    public ArrayList MyList { get; private set; }

как раз сделайте свойство как загерметизированный (или NotInheritable внутри VB.NET) и только для чтения, вот так:

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

также не забудьте сделать резервное поле как readonly:

   private readonly ArrayList mMyList;

но чтобы инициализировать значение mMyList, вы должны инициализировать его только в конструкторе, как в этом примере:

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