& # 8220; Только чтение & # 8221; Свойство Accessor в C #
-
03-07-2019 - |
Вопрос
У меня есть следующий класс:
class SampleClass
{
private ArrayList mMyList;
SampleClass()
{
// Initialize mMyList
}
public ArrayList MyList
{
get { return mMyList;}
}
}
Я хочу, чтобы пользователи могли получать mMyList, поэтому я раскрыл " get " однако через свойство я не хочу, чтобы они вносили изменения в объект (т. е. MyList.Add (new Class ());), чтобы вернуться в мой класс.
Я полагаю, что могу вернуть копию объекта, но это может быть медленно, и я ищу способ, который обеспечит ошибку во время компиляции, информирующую пользователя о том, что он не должен ожидать, что сможет изменить возвращенный объект. значение из собственности.
Возможно ли это?
Решение
С ArrayList вы довольно ограничены, потому что в BCL нет не предназначенного для чтения неуниверсального класса коллекции. Быстрое и грязное решение - вернуть тип IEnumerable. Р>
public IEnumerable MyList
{
get { return mMyList;}
}
Это на самом деле не помешает кому-либо приводить в ArrayList, но также не разрешит редактирование по умолчанию
Вы можете вернуть список только для чтения, вызвав ArrayList.ReadOnly. Однако тип возвращаемого значения - ArrayList, поэтому пользователь все равно сможет компилировать с .Add, но это приведет к ошибке времени выполнения. Р>
Другие советы
Используйте 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
.
возвращает новый объект ReadOnlyCollection < object > (mMyList)
.
Вы также можете сделать ReadOnlyCollection
полем, и оно будет автоматически отражать изменения в базовом списке. Это наиболее эффективное решение.
Если вы знаете, что mMyList содержит только один тип объекта (например, он не имеет ничего, кроме DateTimes),
Вы можете вернуть ReadOnlyCollection < DateTime >
(или некоторый другой тип) для обеспечения дополнительной безопасности типов. Если вы используете C # 3, вы можете просто написать
возвращает новую коллекцию ReadOnlyCollection < DateTime > (mMyList.OfType < DateTime > (). ToArray ())
Тем не менее, это не будет автоматически обновляться с базовым списком, а также будет менее эффективным (он скопирует весь список). Лучший вариант - сделать mMyList общим List < T >
(например, List < DateTime >
)
Вы должны поместить возвращаемое значение в коллекцию только для чтения.
Доступно в .NET v2.0
public ArrayList MyList { get; private set; }
Просто сделайте свойство как Sealed (или NotInheritable в VB.NET) и только для чтения, например, так:
public sealed readonly ArrayList MyList
{
get { return mMyList;}
}
Также не забудьте сделать вспомогательное поле доступным только для чтения:
private readonly ArrayList mMyList;
Но чтобы инициализировать значение mMyList, вы должны инициализировать его ТОЛЬКО в конструкторе, как в этом примере:
public SampleClass()
{
// Initialize mMyList
mMyList = new ArrayList();
}