只读 vs 静态只读澄清

5
我遇到了一个有趣的情况,正在尝试理解。我在类中有一个只读结构体字段。这意味着当我引用它时,它引用的是副本而不是实际的字段,因此当我调用change方法时,它将使用副本进行操作,而原始值将保持不变。
但我观察到的情况并非如此。我只在静态字段上看到了预期的行为。我希望两种类型的字段都能表现出相同的行为。
private struct junk
{
    public int i;

    public void change()
    {
        i += 1;
    }
}

private readonly junk jk;
private static readonly junk jk2;

public Form1()
{
    InitializeComponent();
    jk.change();
    //jk.i is now 1, why? Shouldn't it be changing a copy and not the original jk?
    jk2.change();
    //jk2.i is 0
}

6
可变值类型 - 坚决说 - Damien_The_Unbeliever
3
请删除与 InitializeComponent() 无关的调用,并插入打印 jk.ijk2.i 值的代码,并展示它们的输出结果。我们不关心你认为这些值是什么,我们想要看到这些值实际是什么。 - Mike Nakis
2
(我们还想知道您认为这些值是如何得出的。) - Mike Nakis
2
警告会很好,但是C#编译器没有确保change()具有可观察副作用的管道。一个反例是C++/CLI编译器,它总是假设,这也不会让程序员感到满意。添加static Form1()以查看是否允许改变jk2的值。 - Hans Passant
1个回答

6
我在我的类中有一个只读结构体字段。这意味着当我引用它时,它引用的是副本而不是实际的字段,因此当我调用更改方法时,它将使用副本进行操作,原始字段将保持不变。
这完全不是readonly修饰符的作用。readonly修饰符防止你在除构造函数以外的任何地方为jk赋新值。然后,static修饰符允许你独立于你正在处理的Form1实例重用该值。 话虽如此,无论是readonly还是static都没有造成你所描述的奇怪行为,因为你发布的代码中无法复现这种确切的行为。
看一个简单的控制台应用程序示例(你可以在这里尝试):
public class Program
{
    private readonly junk jk;
    private static readonly junk jk2;

    public static void Main()
    {
        var program = new Program();
        program.jk.change();
        Console.WriteLine(program.jk.i); // prints 0

        jk2.change();
        Console.WriteLine(jk2.i); // prints 0
    }
}

public struct junk
{
    public int i;
    public void change()
    {
        i += 1;
    }
}

然后,正如@Damien_The_Unbeliever所评论的那样,尽可能避免使用可变的struct

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接