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;
}
}
}
我有一个 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;
}
}
}