C# 最佳实践:可编辑状态是一个引用所以仍然连接

C# best practice: Editable state is a reference so still connected

我有一个 CameraComponent class。它包含一个名为 CameraState 的 class。一个简化的例子:

public class CameraState
{
    public float zoom = 1f;
    // a number of other fields, some value types, some reference types...
}

public class CameraGameComponent
{
    private CameraState currentCameraState = new CameraState();

    public CameraState CurrentCameraState
    {
        get { return currentCameraState; }
        set { currentCameraState = value; }
    }
    //...

想法是,另一个 class 可以创建一个新的 CameraState,对其进行设置,然后设置 CurrentCameraState 以使相机使用该新状态。效果不错。

或者其他 class 可以获取 CurrentCameraState,存储它或根据需要更改它(此时代码的其他部分可能会更改 CurrentCameraState),然后设置 CurrentCameraState 以使相机使用它存储状态。

问题在于,当另一个 class 读取 CurrentCameraState 然后更改其状态版本时,相机中的状态也会更改。例如:

// in another class
// Camera.CurrentCameraState.zoom is currently 1f
CameraState state = Camera.CurrentCameraState;
state.zoom = 20f;    // line 1
CameraState testState = Camera.CurrentCameraState;
float testzoom = testState.zoom;    // line 2
// at this point testzoom is 20f, not 1f

我希望第 1 行中缩放的更改不会影响 Camera.CurrentCameraState 中的缩放值,因此在第 2 行 testzoom 的值为 1f。

同理,如果

// in another class, class 1
// Camera.CurrentCameraState.zoom is currently 1f
CameraState state = Camera.CurrentCameraState;

[...]

// elsewhere, in yet another class, class 2
Camera.CurrentCameraState.zoom = 20f;

[...]

// at a later point in class 1
float testzoom = state.zoom;    // line 3
// at this point testzoom is 20f, not 1f

我希望第 3 行的 testzoom 是存储时的状态,即 1f。

我知道为什么会发生这种情况(CurrentCameraState return 是一个参考),我可以想出很多方法来阻止它发生(return CameraState 的新深拷贝 class,使用结构,获取相机 class 来处理状态的存储和恢复等)但我的问题是:

对于这种用法,实现此目的的最佳实践方法是什么?我是否遗漏了一些明显的东西?

听起来您只是想让 CameraState 成为一个值类型(结构)。如果您希望 CameraState 的所有实例都具有此行为,而不仅仅是 CameraGameComponent 中的实例,那么只需使用结构。

如果您需要 CameraGameComponent 中的 CameraState 的行为不同于 CameraState 的所有其他实例,那么您需要更改 CurrentCameraState [=26] 的行为=]. getter 必须 return CameraState 的副本,而 setter 必须设置属性:

public class CameraGameComponent
{
    private CameraState currentCameraState = new CameraState();

    public CameraState CurrentCameraState
    {
        get {
            var cs =  new CameraState{};
            cs.zoom = currentCameraState.zoom;
            return cs;
        }
        set {
            currentCameraState.zoom = value.zoom;
        }
    }
}