我来自C++,发现C++和C#中的指针之间有非常不同的行为。

我惊讶地发现此代码可以编译...甚至...完美地运行。

class C
{
    private readonly int x = 0;
    unsafe public void Edit()
    {
        fixed (int* p = &x)
        {
           *p = x + 1;
        }
        Console.WriteLine($"Value: {x}");
    }
}

这让我感到非常困惑,即使在C++中,我们也有一种机制来保护const对象(C++中的const与C#中的readonly几乎相同,而不是C#中的const),因为我们没有足够的理由通过以下方式任意修改const值:指针。

进一步研究,我发现在C#中没有C++的低级const指针,它类似于:

readonly int* p

在C#中,如果有的话。

然后,p只能读取指向的对象,而不能写入它。

对于const对象,C#禁止尝试检索其地址。

在C++中,任何尝试修改const的尝试都是编译错误或未定义行为。在C#中,我不知道我们是否有可能利用它。

所以我的问题是:
  • 这种行为是否定义明确?虽然我在C#中知道,但C++中没有像UB这样的概念
  • 如果是这样,我应该如何使用它?还是从不使用它?


  • 注意:在注释部分:在C++中丢弃const与该问题无关,因为仅当指向的对象本身不是const时才有效,否则为UB。另外,我基本上是在谈论C#和编译时行为。

    如果您不完全理解该问题,可以要求我提供更多详细信息。我发现大多数人都无法正确理解这一点,也许这是我的不明确之处。

    最佳答案

    我希望可以说,由于unsafe关键字,您只会得到这种意外的行为。不幸的是,至少还有另外两种更改该只读字段的方法,它们甚至不需要不安全的方法。您可以在Joe Duffy的博客文章'When is a readonly field not readonly'中找到有关这些方法的更多信息。

    通过将字段与非只读结构重叠:

    class C
    {
        private readonly int x = 0;
    
        class other_C
        {
            public int x;
        }
    
        [StructLayout(LayoutKind.Explicit)]
        class Overlap_them
        {
            [FieldOffset(0)] public C actual;
            [FieldOffset(0)] public other_C sneaky;
        }
    
        public void Edit()
        {
            Overlap_them overlapper = new Overlap_them();
            overlapper.actual = this;
            overlapper.sneaky.x = 1;
            Console.WriteLine($"Value: {x}");
        }
    }
    

    并通过使用ref参数意外地为this别名(这是从外部完成的):
    class C
    {
        private readonly int x = 0;
    
        public C(int X)
        {
            x = X;
        }
    
        public void Edit(ref C foo)
        {
            foo = new C(1);
            Console.WriteLine($"Value: {x}");
        }
    }
    
    private static void Main()
    {
        var c = new C(0);
        c.Edit(ref c);
    }
    

    这三种方法都是定义明确的C#,您应该避免像瘟疫一样避免使用C#。试想一下,调试代码具有类外产生的复杂别名问题。不幸的是,仍然没有任何令人满意的解决方案来停止C#中的别名问题。

    关于c# - 可以使用指针来修改只读字段吗?但为什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61023196/

    10-11 22:31
    查看更多