In the Design Guidelines for Developing Class Libraries, Microsoft say:
Do not assign instances of mutable types to read-only fields.
It seems natural that if a field is readonly, you would expect to not be able to change the value or anything having to do with it. If I knew that Bar was a readonly field of Foo, I could obviously not say
Foo foo = new Foo();
foo.Bar = new Baz();
But I can get away with saying
foo.Bar.Name = "Blah";
If the object backing Bar is, in fact, mutable. Microsoft is simply recommending against that subtle, counterintuitive behavior by suggesting that readonly fields be backed by immutable objects.
Microsoft has a few such peculiar advices. The other one that immediately springs to mind is not to nest generic types in public members, like List<List<int>>
. I try to avoid these constructs where easily possible, but ignore the newbie-friendly advice when I feel the use is justified.
As for readonly fields - I try to avoid public fields as such, instead going for properties. I think there was a piece of advice about that too, but more importantly there are cases now and then when a field doesn't work while a property does (mostly it has to do with databinding and/or visual designers). By making all public fields properties I avoid any potential problems.
This is legal in C# (simple Console App)
readonly static object[] x = new object[2] { true, false };
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
x[0] = false;
x[1] = true;
Console.WriteLine("{0} {1}", x[0], x[1]); //prints "false true"
Console.ReadLine();
}
that would work. but that wouldn't make sense. bear in mind the variable x is readonly, and has not changed (i.e. the ref of x has not changed indeed). but that's not what we meant when we said "readonly x", is it? so don't use readonly fields with mutable values. It's confusing and counter-intuitive.
I agree with you completely, and I do sometimes use readonly
in my code for mutable reference types.
As an example: I might have some private
or protected
member -- say, a List<T>
-- which I use within a class's methods in all its mutable glory (calling Add
, Remove
, etc.). I may simply want to put a safeguard in place to ensure that, no matter what, I am always dealing with the same object. This protects both me and other developers from doing something stupid: namely, assigning the member to a new object.
To me, this is often a preferable alternative to using a property with a private set
method. Why? Because readonly
means the value cannot be changed after instantiation, even by the base class.
In other words, if I had this:
protected List<T> InternalList { get; private set; }
Then I could still set InternalList = new List<T>();
at any arbitrary point in code in my base class. (This would require a very foolish error on my part, yes; but it would still be possible.)
On the other hand, this:
protected readonly List<T> _internalList;
Makes it unmistakably clear that _internalList
can only ever refer to one particular object (the one to which _internalList
is set in the constructor).
So I am on your side. The idea that one should refrain from using readonly
on a mutable reference type is frustrating to me personally, as it basically presupposes a misunderstanding of the readonly
keyword.
The syntax you are looking for is supported by the C++/CLI language:
const Example^ const obj;
The first const makes the referenced object immutable, the 2nd makes the reference immutable. The latter is equivalent to the readonly keyword in C#. Attempts to evade it produce a compile error:
Test^ t = gcnew Test();
t->obj = gcnew Example(); // Error C3892
t->obj->field = 42; // Error C3892
Example^ another = t->obj; // Error C2440
another->field = 42;
It is however smoke and mirrors. The immutability is verified by the compiler, not by the CLR. Another managed language could modify both. Which is the root of the problem, the CLR just doesn't have support for it.
In the end they are just guidelines. I know for a fact that the people at Microsoft often don't follow all of the guidelines.