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 *const或T&在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值类型的答案.不言而喻,不要在家里这样做.