可以C#转换const吗?

hid*_*yat 2 c# c++ casting

如果一个对象是readonly或const,是否可以转换该对象使其可写?类似于C++ const_cast的东西.

R. *_*des 13

它在C#中是不可能的,就像它在C++中不可能一样.在C++中,如果对象实际上是const,则不能const_cast在不调用未定义的行为的情况下将constness 写出来并写入:

struct foo { const int x; };

foo a;
int& b = const_cast<int&>(a.x);
b = 17; // invokes undefined behaviour
Run Code Online (Sandbox Code Playgroud)

一个readonly在C#字段仅表示该字段本身不能被重新分配.它类似于T *constT&在C++中.您可以通过其成员随意更改引用的对象.

class Foo { public int x; }
class Bar { public readonly Foo y = new Foo(); }

Bar a = new Bar();
a.y.x = 3; // valid
a.y = new Foo(); // invalid
Run Code Online (Sandbox Code Playgroud)

好吧,我不是在说实话.您可以readonly通过反射1欺骗和更改字段:

typeof(string).GetField("Empty").SetValue(null, "bar");
// this effectively makes string.Empty equal to "bar", with disastrous consequences
// It requires full trust though.
// Obviously, it's evil.
Run Code Online (Sandbox Code Playgroud)

如果它是一个const领域,那么即使这个技巧也行不通.

const字段在使用它们的程序集中进行硬编码,而不是保留对原始程序集的引用:

// Assembly A.dll
public class Foo { public static const int X = 42; }

// Assembly B.dll
int y = Foo.X;
// this is the equivalent to:
int y = 42;
Run Code Online (Sandbox Code Playgroud)

这意味着如果重新编译A.dll并将值更改Foo.X为23,则B.dll仍将使用42,直到重新编译为止.

所有这一切,如果你想要一个你想要改变的领域,就不要做readonly.如果你希望它是由类可变的,但是从外部是不可变的,那么将它设为private并添加一个只读属性(注意:这与readonly字段不同):

class Foo
{
    private int bar;
    public int Bar
    {
        get { return bar; }
    }
}
Run Code Online (Sandbox Code Playgroud)

1 不是真正的保证,但它适用于Microsoft实现.如果你想知道为什么这个hack可以工作,你可以阅读Eric Lippert的解释.请务必阅读有关readonly值类型的答案.不言而喻,不要在家里这样做.

  • 实际上在C++中,抛弃constness不会调用未定义的行为.修改const对象,例如通过非const引用或通过强制转换constness创建的指针,可以调用未定义的行为.但只要你不改变const对象,就没有UB.所以在你的例子中,抛弃是完全正常的,尽管是不必要的(cou可以在任何一天将const int赋值给int).如果你试过const_cast <int>(ax)= 5; - 那将是UB. (5认同)