Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When creating an immutable type in .net is it valid to have public fields?

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;
    }
}
like image 496
Simon Avatar asked Dec 20 '22 13:12

Simon


2 Answers

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.

like image 162
O. R. Mapper Avatar answered May 10 '23 20:05

O. R. Mapper


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.

like image 41
supercat Avatar answered May 10 '23 19:05

supercat