可以C#转换const吗?

时间:2011-08-24 11:57:07

标签: c# c++ casting

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

5 个答案:

答案 0 :(得分:12)

在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

C#中的readonly字段仅表示无法重新分配字段本身。它类似于C ++中的T *constT&。您可以通过其成员随意更改引用的对象。

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
嗯,我不是在说实话。您可以通过反射 1

来欺骗和更改readonly字段
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.

如果它是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;

这意味着如果您重新编译A.dll并将Foo.X的值更改为23,那么B.dll在重新编译之前仍会使用42。

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

class Foo
{
    private int bar;
    public int Bar
    {
        get { return bar; }
    }
}

1 这个is not really guaranteed,但它适用于Microsoft实现。如果你想知道为什么这个hack可以工作,你可以阅读Eric Lippert's explanation。请务必阅读有关readonly on value types的答案。不言而喻,不要在家里做这个

答案 1 :(得分:1)

您将无法修改const本身的值。您所能做的就是复制并更改该副本。除非我误解了这个问题......?

请记住,在C#const中,无论如何都是一个非常有限的关键字,你只能在const声明某些内容,并且只能在编译时:

http://msdn.microsoft.com/en-us/library/e6w8fe1b(v=VS.100).aspx

不确定为什么要改变常量。

答案 2 :(得分:1)

没有。参考或值将是只读的。

但是,您可以修改引用的属性,也可以只复制一个值。

答案 3 :(得分:0)

对象不是readonly或const,只有变量。这意味着您只能为这样的变量赋值一次(在const的情况下)或仅在构造所有者对象之前(在readonly的情况下)。

分配给readonly变量的对象仍然可以更改,除非它是不可变的(如string)。

答案 4 :(得分:0)

您可以在 CSharp readonly 中强制转换(与 C++ const 等效)。 CSharp const 可以用 constexpr 翻译成 C++,不能丢弃。

为此,您可以调用 Unsafe.AsRef - 其含义与 C++ const_cast 相同:

using System;

class App{
   static readonly int i = 42;
   static void Main(){
       Console.WriteLine(i);
       System.Runtime.CompilerServices.Unsafe.AsRef(i) = 777;
       Console.WriteLine(i);
   }
}

在 C++ 中看起来是一样的:

#include <iostream>

class App{
public:
    static inline int iStorage= 42;
    static inline const int& i = iStorage;

    static void Main(){
       std::cout << i << '\n';
       *const_cast<int*>(&i) = 777;
       std::cout << i <<'\n';
   }
};

int main(){
    App::Main();
}

仅在 static const 的情况下,C++ 实现允许将数据存储在只读内存中(标准明确允许)。 这通常用于像 int 这样的简单类型 - 原因是没有 constexpr 但希望具有相同的行为 - 因此 static const 有时与 constexpr 具有相同的含义。