Table builder pattern Trying to combine functional style (immutable objects) and flexibility of property setters. For the sake of example, let’s say we have a soil types table with two attributes: Color and Name. I am looking for a way to alternate Names, but not Color. Here is how I solved it:

        // retrieving: all objects are immutable
        SoilTypes types = SoilTypes.Default;
        ISoilType clay1 = types.Clay;
        ISoilType clay2 = types[3];

        // derive an alternated immutable copy
        SoilTypes altTypes = types
            .With(tt =&gt;
            {
                // tt.SensitiveFines.Color is still read only
                tt.SensitiveFines.Name = "Very sensitive fines!";
                tt[2].Name = "Purely Organic soil!";
            });

        // retrieving: everything is immutable
        ISoilType sensitiveFines = altTypes.SensitiveFines;


Where this interface is immutable:

public interface ISoilType
{
    Color Color { get; }
    string Name { get; }
}


And this class is mutable:

public class SoilType : ISoilType
{
    public static implicit operator SoilType((Color Color, string Name) tuple) =&gt;
         new SoilType(tuple.Color, tuple.Name);

    internal SoilType(ISoilType source)
        : this(source.Color, source.Name)
    {
    }

    internal SoilType(Color color, string name)
    {
        Color = color;
        Name = name;
    }

    public Color Color { get; }
    public string Name { get; set; }
}


And this non-generic class is immutable:

public class SoilTypes : SoilTypes&lt;ISoilType&gt;
{
    public static SoilTypes Default = new SoilTypes(
        (White, "Undefined"),
        (Red, "Sensitive Fines"),
        (Green, "Organic Soil"),
        (Blue, "Clay"),
        (Orange, "Silty Clay"));

    public SoilTypes(params SoilType[] types)
        : base(types)
    {
    }

    public SoilTypes With(Action&lt;SoilTypes&lt;SoilType&gt;&gt; update)
    {
        var copy = this
            .Select(t =&gt; new SoilType(t))
            .ToArray();

        update(new SoilTypes&lt;SoilType&gt;(copy));
        return new SoilTypes(copy);
    }
}


while this generic base used in both situations:

public class SoilTypes&lt;TType&gt; : ReadOnlyCollection&lt;TType&gt;
    where TType : ISoilType
{
    internal SoilTypes(TType[] types)
        : base(types)
    {
    }

    public TType Undefined =&gt; this[0];
    public TType SensitiveFines =&gt; this[1];
    public TType OrganicSoil =&gt; this[2];
    public TType Clay =&gt; this[3];
    public TType SiltyClay =&gt; this[4];
}
I'm afraid this is not fully immutable becasue I am able to change the Name with a simple cast:

altTypes.Dump();
((SoilType)altTypes.SensitiveFines).Name = "foo";
altTypes.Dump();


The underlying data type is still SoilType so the interface does not protect the data from being overriden.

Consider a user that writes a function like this one because he doesn't like interfaces :-)

public static void foo(SoilType bar)
{
    bar.Name = "new name";
}


and calls it

foo((SoilType)altTypes.SensitiveFines);
altTypes.Dump();


Name changed. Unfortunatelly I have no idea how to prevent it yet.