C # Поведение ссылки только для чтения - PullRequest
0 голосов
/ 24 октября 2018

Я читал документацию по C # 7.2 здесь , и я столкнулся с этим в отношении ref readonly:

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

Это создало некоторую путаницу для меня (и, возможно, некоторых других), поэтому я хотел бы уточнить поведение сейчас.Предположим, у меня есть структура, определенная следующим образом:

public struct Point3D
{
    private static Point3D origin = new Point3D(0,0,0);

    public static ref readonly Point3D Origin => ref origin;

    public int X { get; set; }
    public int Y { get; set; }
    public int Z { get; set; }

    public static void ChangeOrigin(int x = 0, int y = 0, int z = 0)
    {
        origin = new Point3D(x, y, z);
    }
}

Теперь предположим, что я использовал ref readonly для получения Point3D.Origin и изменил ее:

ref readonly var origin = ref Point3D.Origin;
var originValue = Point3D.Origin;
Point3D.ChangeOrigin(1, 1, 1);

Console.WriteLine("Origin is: ({0}, {1}, {2})", origin.X, origin.Y, origin.Z);
Console.WriteLine("Origin is: ({0}, {1}, {2})", originValue.X, originValue.Y, originValue.Z);

Результат выполнения этого кодаэто:

Origin is: (1, 1, 1)
Origin is: (0, 0, 0)

Это ожидается.Значение в origin обновляется, когда я вызываю ChangeOrigin, тогда как значение в originValue копируется и, следовательно, не изменяется.Мой вопрос касается "защитной копии", упомянутой выше.Почему это необходимо?Значение в origin не может быть изменено без вызова ошибок компилятора, и ссылка обновляется должным образом, когда Point3D.Origin обновляется, поэтому, почему есть дополнительная копия объекта, которая из того, что я собрал, читая документацию,не обновляется?

1 Ответ

0 голосов
/ 24 октября 2018

Вы можете присвоить значение полю только для чтения только в следующих контекстах:

  • Когда переменная инициализируется в объявлении.

    C # пример:

    public readonly int y = 5;
    
  • В конструкторе экземпляра класса, который содержит объявление поля экземпляра.

  • В статическом конструкторе класса, который содержит объявление статического поля.

Эти контексты конструктора также являются единственными контекстами, в которых допустимо передавать поле только для чтения в качестве параметра out или ref.

, если вы используете оператор, подобный следующему примеру:

p2.y = 66; // Error

вы получите сообщение об ошибке компилятора:

Поле, доступное только для чтения, не может быть назначено (кроме как в конструкторе или инициализаторе переменной)

Модификатор readonly при возврате ссылки указывает, что возвращаемая ссылка не может быть изменена.В следующем примере возвращается ссылка на источник.Он использует модификатор readonly, чтобы указать, что вызывающие абоненты не могут изменить источник:

private static readonly Point origin = new Point(0, 0);
public static ref readonly Point Origin => ref origin;

Возвращаемый тип не обязательно должен быть структурой только для чтения.Любой тип, который может быть возвращен с помощью ref, может быть возвращен с помощью ref readonly

Это все прямо из документов, и я надеюсь, что это прояснит это для вас!Удачного кодирования!

Так что, если вы установите (1,1,1) в конструкторе, это будет (1,1,1) вызов изменения с другим методом, как указано выше, вы получите (0,0,0)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...