将公共只读字段用于不可变结构是否有效? [英] Does using public readonly fields for immutable structs work?

查看:12
本文介绍了将公共只读字段用于不可变结构是否有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是声明不可变结构的正确方法吗?

Is this a proper way to declare immutable structs?

public struct Pair
{
    public readonly int x;
    public readonly int y;

    // Constructor and stuff
}

我想不出为什么这会遇到问题,但我只是想确认一下.

I can't think of why this would run into problems, but I just wanted to ask to make sure.

在这个例子中,我使用了整数.如果我改用一个类,但该类也是不可变的,像这样怎么办?这也应该可以正常工作,对吗?

In this example, I used ints. What if I used a class instead, but that class is also immutable, like so? That should work fine too, right?

public struct Pair
{
    public readonly (immutableClass) x;
    public readonly (immutableClass) y;

    // Constructor and stuff
}

(旁白:我知道使用 Properties 更具通用性并且允许更改,但是这个结构体的目的只是存储两个值.我只是对这里的不变性问题感兴趣.)

(Aside: I understand that using Properties is more generalizable and allows changing, but this struct is intended literally to just store two values. I'm just interested in the immutability question here.)

推荐答案

如果您要使用结构体,最佳做法是使它们不可变.

If you're going to use structs, it is a best practice to make them immutable.

将所有字段设为只读是帮助 (1) 证明结构不可变的好方法,以及 (2) 防止意外更改.

Making all the fields readonly is a great way to help (1) document that the struct is immutable, and (2) prevent accidental mutations.

然而,有一个皱纹,这实际上是一个奇怪的巧合,我计划下周写博客.即:对结构字段的只读是谎言.人们期望只读字段不能更改,但它当然可以.struct 字段上的只读"是在其帐户中没有钱的情况下写支票的声明.结构不拥有它的存储空间,它是可以变化的存储空间.

However, there is one wrinkle, which actually in a strange coincidence I was planning on blogging about next week. That is: readonly on a struct field is a lie. One expects that a readonly field cannot change, but of course it can. "readonly" on a struct field is the declaration writing cheques with no money in its account. A struct doesn't own its storage, and it is that storage which can mutate.

例如,让我们以您的结构为例:

For example, let's take your struct:

public struct Pair
{
    public readonly int x;
    public readonly int y;
    public Pair(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
    public void M(ref Pair p)
    {
        int oldX = x;
        int oldY = y;
        // Something happens here
        Debug.Assert(x == oldX);
        Debug.Assert(y == oldY);
    }
}

这里发生了一些事情"是否会发生任何导致违反调试断言的事情?当然.

Is there anything that can happen at "something happens here" that causes the debug assertions to be violated? Sure.

    public void M(ref Pair p)
    {
        int oldX = this.x;
        int oldY = this.y;
        p = new Pair(0, 0);
        Debug.Assert(this.x == oldX);
        Debug.Assert(this.y == oldY);
    }
...
    Pair myPair = new Pair(10, 20);
    myPair.M(ref myPair);

现在会发生什么?违反了断言!this"和p"指的是同一个存储位置.存储位置发生了变化,因此this"的内容发生了变化,因为它们是相同的东西.该结构体无法强制 x 和 y 的只读性,因为该结构体不拥有存储空间;存储是一个局部变量,可以随意改变.

And now what happens? The assertion is violated! "this" and "p" refer to the same storage location. The storage location is mutated, and so the contents of "this" are mutated because they are the same thing. The struct is not able to enforce the read-only-ness of x and y because the struct doesn't own the storage; the storage is a local variable that is free to mutate as much as it wants.

您不能依赖不变式,即结构中的只读字段永远不会发生变化;您唯一可以依赖的是,您无法编写直接更改它的代码.但是通过像这样一些偷偷摸摸的工作,您可以间接地随心所欲地改变它.

You cannot rely on the invariant that a readonly field in a struct is never observed to change; the only thing you can rely on is that you can't write code that directly changes it. But with a little sneaky work like this you can indirectly change it all you want.

另请参阅 Joe Duffy 关于此问题的出色博客文章:

See also Joe Duffy's excellent blog article on this issue:

http://joeduffyblog.com/2010/07/01/when-is-a-readonly-field-not-readonly/

这篇关于将公共只读字段用于不可变结构是否有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆