3

If an object is readonly or const, is it possible to cast that object to make it writable? Something similar to C++ const_cast.

Greg B
  • 14,597
  • 18
  • 87
  • 141
hidayat
  • 9,493
  • 13
  • 51
  • 66

5 Answers5

13

It's not possible in C#, just like it's not possible in C++. In C++, if the object is really const, you cannot const_cast the constness away and write to it without invoking undefined behaviour:

struct foo { const int x; };

foo a;
int& b = const_cast<int&>(a.x);
b = 17; // invokes undefined behaviour

A readonly field in C# only means that the field itself cannot be reassigned. It's akin to T *const or T& in C++. You can change the referenced object at will through its members.

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

Well, I'm not telling the whole truth. You can cheat and change readonly fields through reflection1:

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.

If it is a const field however, not even this trick will work.

const fields are hardcoded in assemblies that use them, instead of keeping references to the original assembly:

// 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;

This means that if you recompile A.dll and change the value of Foo.X to 23, B.dll will still use 42 until it is recompiled.

All that said, if you want to have a field that you want to change, just don't make it readonly. If you want it to be mutable by the class, but immutable from the outside, make it private and add a read-only property (note: this is not the same as a readonly field):

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

1This is not really guaranteed, but it works on the Microsoft implementations. If you're wondering why this hack works at all, you can read Eric Lippert's explanation. Be sure to also read the answer about readonly on value types. And it goes without saying, don't do this at home.

Community
  • 1
  • 1
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • "unlike in C++" not true. It's just that C# references behave more like pointers and `readonly` is more like `Bar*const` rather than `const Bar*`. – Yakov Galka Aug 24 '11 at 12:10
  • 6
    Actually in C++ casting away constness does not invoke undefined behaviour. Modifying a const object, for example through a non-const reference or pointer created by casting away constness, is what invokes undefined behaviour. But as long as you don't change the const object, there is no UB. So in your example the casting away is completely fine, albeit unnecessary (cou can assign const int to int any day). If you tried const_cast(a.x)=5; - that would be UB. – AndrzejJ Aug 24 '11 at 12:22
  • Thanks all for the comments. I hope I fixed all the not so correct details :) – R. Martinho Fernandes Aug 24 '11 at 13:30
1

You won't be able to amend the value of the const itself. All you can do is take a copy and change that copy. Unless I'm misunderstanding the question...?

Bear in mind that in C# const is quite a limited keyword anyway, you can only declare certain things as const and only at compile time:

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

Not sure why you'd want to mutate a constant.

Adam Houldsworth
  • 63,413
  • 11
  • 150
  • 187
1

No. The reference or value will be read only.

You can however modify the properties of references or you could just make a copy of a value.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
0

You can cast in CSharp readonly away (which is equilant to C++ const). CSharp const could be translated to C++ with constexpr which can't be casted away.

To do so you can call Unsafe.AsRef - which has the same meaning as 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);
   }
}

The same would look in C++ like:

#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();
}

Just in case of static const C++ implementations are allowed to store the data in readonly-memory (which is explicitly allowed by the standard). This is done usually for simple types like int - the reason is that there was no constexpr but the same behaviour was wished - therefore static const has sometimes the same meaning as constexpr.

Bernd
  • 2,113
  • 8
  • 22
0

Objects are not readonly or const, only variables are. That means you can assign a value to such a variable only once (in the case of const) or only until the owner object is constructed (in the case of readonly).

The object assigned to a readonly variable can still be changed, though, unless it's immutable (like string).

Gabe
  • 84,912
  • 12
  • 139
  • 238