2009-03-06 15 views
19

У меня есть следующий класс:«только для чтения» Property Accessor в C#

class SampleClass 
{ 
    private ArrayList mMyList; 

    SampleClass() 
    { 
     // Initialize mMyList 
    } 

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

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

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

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

+0

Связанные вопрос: http://stackoverflow.com/questions/681287/how-to-make-a-reference-type-property-readonly –

+2

Есть ли список : ReadOnlyCollection 'в .NET 4.5 изменить все это? http://www.infoq.com/news/2011/10/ReadOnly-WInRT/ –

ответ

25

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

public IEnumerable MyList 
    { 
     get { return mMyList;} 
    } 

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

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

1

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

19

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

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

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

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

Reference

+2

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

+0

-1, OP: «Я ищу способ, который обеспечит ошибку ** компиляции-времени **» –

+0

Без копирования на ReadOnlyCollection, которое он также сказал, что он хочет избежать - я выбираю принудительное чтение, только притворяясь, что он только что прочитан. Выполнение обоих на самом деле, вероятно, лучше. – tvanfosson

-3

Просто сделайте свойство, как Sealed (или NotInheritable в VB.NET) и только для чтения, например:

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

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

private readonly ArrayList mMyList; 

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

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

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

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

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

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

+0

* Это * является правильным - желаю, чтобы я мог голосовать дважды. Любая проблема с вызовом 'yield break' после цикла? – Jay

+0

@Jay: нет необходимости в явном «перерыве выхода», после цикла. Конец метода подразумевает конец 'Enumerator' (и' MoveNext' будет корректно возвращать 'false'). –

+0

С помощью этого решения пользователь не теряет функциональность ArrayList, например, быстрый случайный доступ и быстрый подсчет? –

4

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

return new ReadOnlyCollection<object>(mMyList).

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

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

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

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

0

Доступна с .NET v2.0

public ArrayList MyList { get; private set; } 
+0

Вы все равно сможете использовать Добавить в существующем списке. –

 Смежные вопросы

  • Нет связанных вопросов^_^