Member 13566383 Ответов: 1

Запись в переменные только для чтения


В следующем коде я определил класс Polynomial в котором содержится массив, обозначенные знаком readonly.
Я определил свойство read. Свойство записи не может быть определено из-за ошибки компилятора CS0191. Это нормально.
Но если я попытаюсь написать, используя (несуществующее) свойство write, например p.Coeff[2] = 19 это работает! Как такое может быть?
Я сделал еще несколько тестов:
A: я определил индексатор. Компилятор не мешает мне определять свойство записи. Он может быть использован для модификации readonly данные участника.
Б: я использовал свой Polynomial объект p в качестве параметра метода UsePolynomial с ключевым словом in Я понимаю, что аргумент передается по ссылке, чтобы избежать ненужных операций копирования, если объект параметра не будет изменен. Компилятор не должен допускать никаких операций, изменяющих объект. Но нет никакой проблемы изменить p. Любые изменения, внесенные в вызываемый метод, доступны после возврата из вызова.
Вот моя программа:
namespace PolyTest
{
    class Program
    {
        public class Polynomial
        {
            readonly private double[] coeff;
            public double[] Coeff { get => coeff;} // Does not allow set property because coeff is readonly (CS0191)
            public double this[int i] { get => coeff[i]; set => coeff[i] = value; }
            public Polynomial(double c0, double c1, double c2)
            {
                coeff = new double[] { c0, c1, c2 };
            }
        }
        static void Main(string[] args)
        {
            Polynomial p = new Polynomial(1, 2, 3);
            UsePolynomial(p);
            double val = p[2];          // val = 17 (or 18 if the last line in UsePolynomial is uncommented)
        }

        static void UsePolynomial(in Polynomial p)
        {
            double val1 = p.Coeff[2];   // val1 = 3  OK
            double val2 = p[2];         // Val2 = 3  OK
            p.Coeff[2] = 17;            // Why is that possible?
            //p[2] = 18;                  // Why is that possible?
        }
    }
}


Что я уже пробовал:

То, что я попробовал, вы можете прочитать в вопросе.

1 Ответов

Рейтинг:
6

phil.o

Только для чтения применяется только к самой переменной массива, но не для членов массива. Вы не можете изменить переменную и заставить ее указывать на другой массив, вот и все.

Решение для предотвращения изменения элементов массива состоит в том, чтобы скрыть сам массив извне и избавиться от установщика в свойстве index-accessor:

public class Polynomial
{
   readonly private double[] coeff;

   public double this[int i] { get => coeff[i]; }

   public Polynomial(double c0, double c1, double c2)
   {
      coeff = new double[] { c0, c1, c2 };
   }
}

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


Member 13566383

Мой массив является частным и поэтому скрыт от внешнего мира. Удаление сеттера в свойстве index-accessor или полное удаление индексатора не решает проблему.
Если я это сделаю, то все равно смогу использовать (не существующий??) метод набора p.Coeff[2] = 17;
Просто попробуй.

phil.o

Да, потому что вы предоставляете свойство самому массиву (public double[] Coeff { get => coeff;}- Убери его, и все будет в порядке.

Member 13566383

Хорошо, я думал, что вы рекомендовали удалить мою вторую строку кода в классе Polynomial, а не первую.
Теперь поведение таково, как и ожидалось (и я даже начинаю понимать, почему).