So when designing an immutable class should it use get properties as such
public sealed class Person
{
readonly string name;
readonly int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public string Name
{
get { return name; }
}
public int Age
{
get { return age; }
}
}
Or is it valid to expose public readonly fields
public sealed class Person
{
public readonly string Name;
public readonly int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
While both options will leave you with objects whose fields cannot be changed from the outside, the same guidelines apply for immutable objects as otherwise:
Using properties instead of publicly exposing your fields is still an advantage; you are not checking any input values, but still, future versions of your type might compute some of the values rather than read them directly from an internal field. By using properties, you hide that implementation detail and hence increase your flexibility for future changes.
One major problem with public readonly
class fields in .net is that the from the perspective of outside code, the only thing the readonly
declaration does is mark the field with a readonly attribute (I forget the spelling and casing). Although some languages will honor such attributes in outside code, a language can ignore such attributes if it so chooses. If an object with public readonly
fields is exposed to code written in a language that ignores the readonly attribute, that code could write to such fields just as easily as if the attribute didn't exist.
Structures are a different matter. If a struct stored in field foo
has a field of its own named boz
, then code which can write to foo
can write to foo.boz
, and code which cannot write to foo
cannot write to foo.boz
, regardless of whether boz
is public or private, or whether it is intended to be mutable or immutable. This is because if foo1
is a struct of the same type, the statement foo = foo1
does not make foo
refer to the same instance as foo1
, but rather works by mutating all of the public and private fields in foo
to match the values of corresponding fields in foo1
.
Boxed value types are even worse; if one has an Object
which holds a boxed instance of any value type, the value may be replaced with another of that type. Even supposedly-immutable types like Int32
, when boxed, behave as mutable reference types.
Consequently, when using structure types, one should enforce immutability by storing the structures in private fields of the precise structure type. Attempting to make struct fields immutable can make instances of the type more of a nuisance to work with, but will have no real effect on the mutability or immutability of struct instances.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With