For my project I am trying to create a single global store to serve a mutable state like this:
  // Immutable program state
  sealed public class State : IEquatable<State> {
    public State(ClientsConnections clientsConnections, ImmutableList<string> ids) {
      this.ClientsConnections = clientsConnections;
      this.Ids = ids;
    }
    public readonly ClientsConnections ClientsConnections; // ClientsConnections is immutable
    public readonly ImmutableList<string> Ids; // also immutable
    public override int GetHashCode() => HashCode.Combine(AgentsConnections.GetHashCode(), Ids.GetHashCode());
    public override bool Equals(object obj) { var o = obj as State; return o is null ? false : ClientsConnections.Equals(o.ClientsConnections) && Ids.Equals(Ids); }
    public bool Equals(State o) => object.Equals(this, o); 
    public static bool operator ==(State o1, State o2) => object.Equals(o1, o2); 
    public static bool operator !=(State o1, State o2) => !object.Equals(o1, o2);
  }
  // Store is a mutable singleton
  sealed public class Store {
    readonly object stateLock = new object();
    public Store() => this.State = new State(new ClientsConnections(), ImmutableList<string>.Empty);
    public State State { get; private set; }
    public void SetState(Func<State, State> f) { lock (stateLock) State = f(State); }
  }
I then use it in the code like this:
Thread1 - f1() { 
  var currState=Store.State; 
  log(currState.ids);
}
Thread2 - f2() { 
  Store.SetState(currState => {
    var newids = currState.Ids.Add("hello");
    return new State(currState.ClientsConnections, newids);
  });
}
Questions:
Is this code thread safe ? in particular do I need to lock the Store.State getter ? my reasoning is since the getter does an atomic assignment copying the state reference by value then I do not need to lock it here ?
Can I/should I use ImmutableInterlocked here ?