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;
}
}
Basically no. But you can ease the life by switching to records which allow easier creation and management of immutable data-types:
Notes:
withexpression still shallow-copies properties so use records for nested data types.For "optional" properties you can use
init-only properties:C# record - using with keyword to modify properties