Как я могу убедиться, что этот частный массив только для чтения является частным и доступен только для чтения? - PullRequest
1 голос
/ 04 января 2011

Я пытаюсь выяснить, как я могу успешно изменить массив «только для чтения». Приведенный ниже код работает успешно, но я не совсем понимаю, почему разыменование массива private / readonly допустимо, как указано ниже:

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      MyClass myClass = new MyClass();
      myClass.Time[5] = 5; // Why is this legal? How can I make it illegal?
    }
  }

  public class MyClass
  {
    private readonly uint[] time;
    public IList<uint> Time
    {
      get { return time; }
    }

    public MyClass()
    {
      time = new uint[7];
    }
  }
}

Как я отмечал выше, я ожидаю, что Time [5] будет незаконным из-за того, что в общедоступном IList Time нет установщика.

Как я могу изменить MyClass, чтобы убедиться, что не разрешено делать myClass.Time[5]?

Примечание: Я уточнил цель этого вопроса, вначале мне было неясно, что намерение сделать это НЕЗАКОННЫМ. И я хочу понять, почему это законно, в первую очередь, как есть.

Ответы [ 3 ]

5 голосов
/ 04 января 2011

Как я отмечал выше, я бы ожидал, что Время [5] будет незаконным из-за Дело в том, что публичный IList Time не есть сеттер.

Отсутствие установщика означает, что вы не можете назначить NEW ARRAY для вспомогательного поля свойства, но это не значит, что вы не можете изменить ссылку на массив CURRENT, на который указывает вспомогательное поле.

Кроме того, как я могу создать массив в конструкторе, который только для чтения и неизменяем за пределами этот класс?

Вы можете создать поле только для чтения на этапе объявления или в конструкторе класса согласно MSDN .

Что касается того, как это исправить, в следующей статье MSDN обсуждается именно эта проблема и некоторые способы ее устранения. Я не уверен, каковы ваши требования, но я бы порекомендовал изучить реализацию пользовательской коллекции, используя ReadOnlyCollectionBase , затем передать ее, или вы можете использовать ReadOnlyCollection<T>. Ссылка на ReadOnlyCollectionBase предоставляет пример реализации.

2 голосов
/ 04 января 2011

readonly означает, что само поле не может быть изменено (то есть вы не можете сказать «this.time = new uint [10]» вне конструктора). Массивы являются изменяемыми объектами, поэтому, если у вас есть ссылка на массив, владелец этой ссылки может изменять значения, хранящиеся в этом массиве.

readonly поля доступны для записи только в конструкторе (включая инициализаторы полей)

Два варианта для вас:

  • Сделайте поверхностную копию массива в свойстве Time, чтобы вызывающие абоненты не могли изменить вашу копию массива
  • Используйте ReadOnlyCollection, чтобы вообще предотвратить изменения
0 голосов
/ 04 января 2011

Свойство Time не имеет установки, поэтому вы не сможете сделать что-то вроде этого:

static void Main(string[] args)
{
  MyClass myClass = new MyClass();
  myClass.Time = new List<uint>();
}

но вы можете использовать индексатор, поэтому время [5] допустимо.

Кроме того, как я могу создать массив в конструкторе, который доступен только для чтения и неизменен за пределами этого класса?

поля только для чтения могут быть инициализированы только в конструкторе. Инициализация сразу после объявления аналогична инициализации в конструкторе.

...