Reputation: 3791
I have an object shared between concurrent Tasks. It's for creating different JSONs using the same set of properties. Here is a simplified example of its class: (I call it builder but it's not really following the builder pattern.)
class Builder {
public string part1;
public string part2;
//More parts...
public JSON BuildA(){
return new Serialize(TypeA({"1": part1, "2": part2}));
}
public JSON BuildB(){
return new Serialize(TypeB(part1.ToString(), part2 + part3));
}
//More Building methods
}
The parts are initialized before the builder being passed to the tasks. The problem is in some tasks I might want to locally overwrite one or two properties before building. Since the builder is shared between tasks, these changes causes unwanted side effects on other tasks.
Task.Run(() => MethodA(builder));
Task.Run(() => MethodB(builder));
Task.Run(() => MethodC(builder));
Response MethodA(Builder builder){
builder.SetPart1(10);
builder.SetPart16(false);
JSON = builder.BuildC();
//do http request stuffs
}
Besides deep cloning my builder, is another way to make change or overwrites to an shared object while preventing side effect?
Note: I'm using .NET 6
For now, what I can think of is passing a builder object as local property overwrites and modify every single getter and places that invokes the getter:
JSON = builder.Build(new Builder(){part1=10, part16=false})
class Builder {
public string getPart1(Builder overwrites){
return overwrites.part1 ?? part1;
}
}
Upvotes: 0
Views: 98
Reputation: 142173
Besides deep cloning my builder, is another way to make change to an shared object while preventing side effect?
Basically no. But you can ease the life by switching to records which allow easier creation and management of immutable data-types:
var builder = new Builder("one", "two");
var newBuilder = builder with { Part1 = "new" };
record Builder(string Part1, string Part2) {
public JSON BuildA(){
return new Serialize(TypeA({"1": part1, "2": part2}));
}
public JSON BuildB(){
return new Serialize(TypeB(part1.ToString(), part2 + part3));
}
}
Notes:
with
expression still shallow-copies properties so use records for nested data types.
For "optional" properties you can use init
-only properties:
var newBuilder = builder with { Part1 = "new", I = 5};
record Builder(string Part1, string Part2) {
public int I { get; init; }
// ...
}
Upvotes: 0