简体   繁体   English

C# ref 的行为只读

[英]C# Behavior of ref readonly

I was reading documentation on C# 7.2 here and I came across this in regards to ref readonly :我在阅读文档的C#7.2 在这里,我在关于跨此次来到ref readonly

The compiler enforces that the caller can't modify the reference.编译器强制调用者不能修改引用。 Attempts to assign the value directly generate a compile-time error.尝试直接分配值会生成编译时错误。 However, the compiler can't know if any member method modifies the state of the struct.但是,编译器无法知道是否有任何成员方法修改了结构体的状态。 To ensure that the object isn't modified, the compiler creates a copy and calls member references using that copy.为了确保对象不被修改,编译器创建一个副本并使用该副本调用成员引用。 Any modifications are to that defensive copy.任何修改都针对该防御性副本。

This generated some confusion for me (and possibly some others), so I'd like to clarify the behavior now.这给我(可能还有其他一些人)带来了一些困惑,所以我现在想澄清一下这种行为。 Suppose I have a struct defined like this:假设我有一个这样定义的结构:

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);
    }
}

Now, suppose I used ref readonly to get Point3D.Origin and modified it:现在,假设我使用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);

The result from running this code is:运行这段代码的结果是:

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

This is expected.这是预期的。 The value in origin is updated when I call ChangeOrigin whereas the value in originValue is copied and therefore doesn't change.当我调用ChangeOrigin时, origin的值被更新,而originValue的值被复制,因此不会改变。 My question is in regards to the "defensive copy" mentioned above.我的问题是关于上面提到的“防御性副本”。 Why is this necessary?为什么这是必要的? The value in origin can't be changed without invoking compiler errors and the reference is updated properly when Point3D.Origin updates so what reason is there to have an extra copy of the object, which from what I gathered by reading the documentation, isn't updated?在不调用编译器错误的情况下无法更改origin的值,并且当Point3D.Origin更新时引用会正确更新,所以有什么理由拥有对象的额外副本,从我通过阅读文档收集的内容来看,不是'更新了吗?

You can assign a value to a readonly field only in the following contexts:您只能在以下上下文中为只读字段赋值:

  • When the variable is initialized in the declaration.在声明中初始化变量时。

    C# example: C# 示例:

     public readonly int y = 5;
  • In an instance constructor of the class that contains the instance field declaration.在包含实例字段声明的类的实例构造函数中。

  • In the static constructor of the class that contains the static field declaration.在包含静态字段声明的类的静态构造函数中。

These constructor contexts are also the only contexts in which it is valid to pass a readonly field as an out or ref parameter.这些构造函数上下文也是唯一可以将 readonly 字段作为 out 或 ref 参数传递的上下文。

if you use a statement like the following example:如果您使用类似以下示例的语句:

p2.y = 66; // Error

you will get the compiler error message:您将收到编译器错误消息:

A readonly field cannot be assigned to (except in a constructor or a variable initializer)不能将只读字段分配给(构造函数或变量初始值设定项中除外)

The readonly modifier on a ref return indicates that the returned reference cannot be modified. ref 返回上的 readonly 修饰符指示不能修改返回的引用。 The following example returns a reference to the origin.以下示例返回对原点的引用。 It uses the readonly modifier to indicate that callers cannot modify the origin:它使用 readonly 修饰符来指示调用者不能修改原点:

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

The type returned doesn't need to be a readonly struct.返回的类型不需要是只读结构。 Any type that can be returned by ref can be returned by ref readonly可以由 ref 返回的任何类型都可以由 ref readonly 返回

This is all straight from the DOCs, and I hope it clarifies it for you!这都是直接来自 DOC,我希望它为您澄清! Happy coding!快乐编码!

So if you set (1,1,1) in the constructer, it will be (1,1,1) calling a change with a different method, as above, you get (0,0,0)因此,如果您在构造函数中设置(1,1,1) ,它将是(1,1,1)使用不同的方法调用更改,如上所述,您将得到(0,0,0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM