I've been working on creating a class and suddenly a thought came to my mind of what is the difference between the two codes:
public readonly string ProductLocation;
AND
public string ProductLocation
{
get;
private set;
}
Can you guys give me idea when to use the following better. thanks.
The first is a field whose value can be set only at instantiation.
The second is a property whose value can be set at any time (but only by its containing object).
Correction: The property can be set at any time by any instance of the same class (and not only by its containing object).
The first one (using
readonly
) will mean that the object can't even modify its own field's value, once the object has been instantiated, and others can never modify it.The second one (using
private set
) will mean that object can modify the value of its field after it's been instantiated, but others can never modify it.I would use the former for something that you know will not change, and use the latter for something where the value may change, but you don't want others to change it.
The first one is a read-only field, while the second one gets compiled as a pair of methods (and all reads of the property
ProductLocation
gets compiled into calls to the correspondingget
method and writes to it gets compiled into calls to theset
method; internally, these methods will read from / write to an internal, automatically generated, non-read-only field). I'd say the most important difference is thread-safety! (how? read on!)The basic usage of the class will look exactly the same: code in other classes will only be able to read the value, not change it. Also, the code to read the value will look exactly the same (for example,
print(myInstace.ProductLocation)
; here, you cannot tell how it has been declared, cool, eh?)The first, most trivial difference is that the property with private setter allows for instances of the same class to modify the value, while in the case of the readonly property, not even the object itself will be able to change the value.
Now, for the thread-safety. The
readonly
attribute on the field will change its memory visibility semantics when you are working with multiple threads (just like Java'sfinal
fields).A
readonly
field can only be assigned to at declaration or in the constructor. The value assigned to areadonly
field cannot be changed (at least not in a normal way) and it is guaranteed that every thread will see the correctly, initialized value after the constructor returns. Therefore, areadonly
field is inherently thread-safe.To achieve the same thread-safety with the property, you'd have to add some synchronization on your code, which is error-prone. It might lead to dead-locks, data races or reduced performance, depending on the case, and especially if you are not experienced.
So, if the value represents something that semantically cannot be changed after the object's construction, you should not declare a private setter (this would imply that the object might change it). Go for the readonly field (and maybe declare it private and declare a public property with only a getter accessing the field! This is actually the preferred form, since it is not good to expose fields, it is better to only expose methods -- there are many reasons explaining why in this answer)
With C# 6.0 auto-property initializer there is less boilerplate way of doing
Which is
This is readonly. Only initialized from constructor or inline. It cannot be edited after initialization. (Immutable from anywhere)
However, if you use private set;
This is readonly from outside. But can be initialized anytime anywhere within the class itself. And can be edited within its life cycle by the class itself. (Mutable from class, immutable from outside)
Generally, it is not encouraged in .NET to expose member fields publicly, those should be wrapped by a property. So let's assume you might have
vs
In this setup, and ignoring what one might be able to accomplish via reflection, the semantics are that in the first case, the
productLocation
variable can only be initialized in place and in the class constructor. Other members of the class cannot alter the value. External consumers have no ability to set the value.In the second version, external consumers continue to have no access towards setting the value. However, the class itself can change the value at any time. If all you have is a DTO (that is, a class that only transports data, it has no logic expressed via methods), then this is essentially not all that different from the
readonly
version. However, for classes with methods, those methods could alter the value behindProductLocation
.If you want to enforce the concept of an immutable field post-construction, use
readonly
. But for a DTO, I might go for theprivate set;
option, mainly because it is less boilerplate code.