9

The general guidance for C# is to always use a property over a public field. This makes sense- by exposing a field, you're exposing a lot of implementation detail. With a property, you encapsulate that detail so it's hidden from consuming code, and implementation changes are decoupled from interface changes.

However, I'm wondering if there is sometimes a valid exception to this rule when dealing with the readonly keyword. By applying this keyword to a public field, you make an extra guarantee: immutability. This is not just an implementation detail, immutability is something that a consumer might be interested in. Using a readonly field makes it part of the public contract, and something that cannot be broken by future changes or inheritance without also having to modify the public interface. That's something that a property can't offer.

So is guaranteeing immutability a legitimate reason to choose a readonly field over a property in some cases?

(For clarification, I'm certainly not saying you should always make this choice just because the field happens to be immutable at the moment, only when it makes sense as part of the class's design and it's intended usage to include immutability in its contract. I'm mostly interested in answers focussing on whether this may be justified, rather than specific cases where it's not, such as when you need the member to be on an interface, or want to do lazy-loading.)

  • 1
    @gnat Just to clarify, by "ReadOnly Property" they're using VB.NET terminology which means a property with no setter, not a readonly field. For the purposes of my question, the two options which that question compares are equivalent- they're both using properties. – Ben Aaronson Jul 6 '15 at 0:53
5

Public static readonly fields are certainly okay. They are recommended for certain situations, like when you want a named, constant object but you can't use the const keyword.

Readonly member fields are a bit trickier. There isn't much advantage gained over a property without a public setter, and there is a major disadvantage: fields cannot be members of interfaces. So if you decide to refactor your code to operate against an interface instead of a concrete type, you will have to change your readonly fields to properties with public getters.

A public non-virtual property without a protected setter provides protection against inheritance, unless the inherited classes have access to the backing field. You can completely enforce that contract in the base class.

Not being able to change the "immutability" of the member without changing the public interface of the class is not much of a barrier in this case. Usually if you want to change a public field into a property, it goes smoothly except that there are two cases you have to deal with:

  1. Anything that writes to a member of that object, like: object.Location.X = 4 is only possible if Location is a field. This is not relevant for a readonly field though, because you can't modify a readonly struct. (This is assuming Location is a value type - if not then this issue wouldn't apply anyway because readonly doesn't protect against that sort of thing.)
  2. Any call to a method that passes the value as out or ref. Again, this is not really relevant for a readonly field, because out and ref parameters tend to get modified, and it's a compiler error anyway to pass a readonly value as out or ref.

In other words, although converting a readonly field to a readonly property breaks binary compatibility, other source code would only need to be recompiled without any changes to handle this change. That makes the guarantee really easy to break.

I don't see any advantages to the readonly member field, and the inability to have that sort of thing on an interface is enough of a disadvantage for me that I wouldn't use it.

  • Out of interest, why are public static readonly fields okay? Is it just because ruling out instance methods removes most of the use-cases for properties on immutable fields (like hit-counting, lazy-loading, etc.)? – Ben Aaronson Jul 7 '15 at 15:34
  • The main disadvantage of a public readonly field vs. readonly property is gone - static members can't be part of interfaces so they are on similar footing. A readonly static property either needs storage that gets initialized or it needs to rebuild its return value every time it's called, whereas a readonly field will have simpler syntax and be initialized by the static constructor. So I think a public static readonly field has the potential for greater optimization by the JIT with none of the disadvantages that you would normally have from exposing a field. – Erik Jul 7 '15 at 15:53
2

From my experience, the readonly keyword is not the magic it promises to.

For example, you have a class where the constructor used to be simple. Given the usage, (and the fact that some of the class properties/fields are immutable after construction) you might think that it does not matter, so you used the readonly keyword.

Later, the class become more complex, and so is its constructor. (Let's say this happens in a project that is either experimental or has a high enough velocity zooming out of scope/control but you need to make it work somehow.) You will find that fields that are readonly can only be modified inside the constructor - you can't modify it in methods even if that method is only called from a constructor.

This technical limitation has been acknowledged by the designers of C#, and might be fixed in a future version. But until it is fixed, the use of readonly is more restrictive and might encourage some bad coding style (putting everything in the constructor method).

As a reminder, neither readonly nor non-public-setter property provides any guarantee of a "fully initialized object". In other words, it is the designer of a class that decides what "fully-initialized" means, and how to protect it against inadvertent use, and such protection is generally not foolproof, meaning that someone might find a way around it.

1

Fields are ALWAYS implementation details. You don't want to expose your implementation details.

A fundamental tenet of software engineering is that we don't know what the requirements will be in the future. While your readonly field may be good today, there is nothing to suggest that it will be a part of tomorrow's requirements. What if tomorrow there is a need to implement a hit counter to determine how many times that field is accessed? What if you need to allow sub-classes to override the field?

Properties are so easy to use and are so much more flexible than public fields that I can't think of a single use case where I would both pick c# as my language and use public readonly fields on a class. If performance was so tight that I couldn't take the hit of the extra method call, I'd probably be using a different language.

Just because we can do something with the language doesn't mean we should do something with the language.

I actually wonder whether the language designers regret allowing fields to be made public. I can't remember the last time I even considered using non-const public fields in my code.

  • 1
    I do understand the importance of building in future flexibility, but surely if I write a class like, say, Rational, with public, immutable Numerator and Denominator members, I could be extremely confident that those members won't require lazy-loading or a hit counter or similar? – Ben Aaronson Jul 6 '15 at 13:32
  • But can you be confident that the implementation using float types for the Numerator and Denominator won't need to be changed to doubles? – Stephen Jul 6 '15 at 22:35
  • 1
    Well, er, no, they definitely should be neither float nor double. They should be int, long or BigInteger. Maybe those need to change... but if so they'd need to change in the public interface too, so really using properties adds no encapsulation around that detail. – Ben Aaronson Jul 7 '15 at 11:29
-3

No. It is not a justification.

Using the readonly as a guaranty of inmutability in not a justification is more like a hack.

Readonly means the value is assigned by a constructor o when the variable is defined.

I think it will be a bad practice

If you really want to guaranty immutability use an interface it has more pros than cons.

Simple interface example: enter image description here

  • 1
    "use an interface" How? – Ben Aaronson Jul 6 '15 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.