防止任务中共享对象的本地更改引起的副作用

问题描述 投票:0回答:1

我有一个在并发任务之间共享的对象。它用于使用同一组属性创建不同的 JSON。这是其类的简化示例:(我将其称为构建器,但它并没有真正遵循构建器模式。)

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
}

问题是在某些任务中,我可能想在构建之前在本地更改一两个参数。由于构建器在任务之间共享,因此这些更改会对其他任务造成不必要的副作用。

Task.Run(() => MethodA(builder));
Task.Run(() => MethodB(builder));
Task.Run(() => MethodC(builder));

Response MethodA(Builder builder){
    builder.SetPart4(10);
    builder.SetPart16(false);
    JSON = builder.BuildC();
    //do http request stuffs
}

除了深度克隆我的构建器之外,还有另一种方法可以在防止副作用的同时更改共享对象吗?

注意:我使用的是.NET 6


目前,我能想到的是传递一个对象作为本地属性,覆盖并修改每个 getter 以及调用 getter 的每个位置:

JSON = builder.Build(new Overwrites(){part4=10, part16=false})

class Builder {
    public string getPart1(Overwrites overwrites){
        return overwrites.part1 ?? part1;
    }
}
c# concurrency task side-effects shared-resource
1个回答
0
投票

除了深度克隆我的构建器之外,还有另一种方法可以在防止副作用的同时更改共享对象吗?

基本上没有。但是您可以通过切换到记录来简化生活,它可以更轻松地创建和管理不可变数据类型:

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));
    }
}

备注:

  1. with
    表达式仍然浅复制属性,因此请使用嵌套数据类型的记录。

  2. 对于“可选”属性,您可以使用

    init
    仅限属性:

    var newBuilder = builder with { Part1 = "new", I = 5};
    
    record Builder(string Part1, string Part2) {
        public int I { get; init; }
        // ...
    }
    
  3. C#记录-使用with关键字修改属性

© www.soinside.com 2019 - 2024. All rights reserved.