使值类型保持同步、依赖项属性、引用、事件或重新设计

本文关键字:事件 引用 属性 类型 依赖 同步 | 更新日期: 2023-09-27 18:36:39

问题:

我有一个值类型(结构),需要保存在由不同类更新的类中。

有效解决此问题的"C#"方法是什么?

方法

我在下面放了基本的"归结"代码。似乎可以通过 3 种方式解决:

  1. 使"矩阵"成为依赖属性
  2. 发送"模型"而不是"矩阵"
  3. 引发控制器订阅的模型更改事件,然后更新 model.matrix
  4. 这种方法

我对 C# 相对较新,并且来自C++背景,我只会发送一个指向位置的指针(实际上似乎是 4)。然而,它感觉非常"非C#",回头看感觉像"未设计"!

然而,我的假设是 1:d ependency 属性(看起来像"C#"方式)似乎它们或多或少以相同的方式回避设计,我担心间接程度。

我目前对 2 的问题是修饰符负责更新"矩阵",他们实际上不需要了解模型中的其他所有内容,理想情况下甚至不需要处理它。

3感觉像是2的手卷版本,但感觉会更有效率

关于数据:

"矩阵"的多个实例将被大量读取,但一次也只会写入 1/2,最多在鼠标移动事件期间。

示例代码

class Model
{
    glm.mat4 position; //mat4 is a struct i.e. a value type
}
class MouseControll
{
    MatrixModifiyer Modifier = new MatrixModifiyer()
    MouseControll(Model model)
    {
        Modifier.BindToMatrix(model.matrix);
    }
    //invoke modifier based on mouse events
}
class InterfaceControll
{
    MatrixModifiyer Modifier = new MatrixModifiyer()
    InterfaceControll(Model model)
    {
        Modifier.BindToMatrix(model.matrix);
    }
    //invoke modifier based on button events
}
class MatrixModifiyer
{
    glm.mat4 camera;       //how do I have position in sync with camera?
    glm.vec2 position;
    void BindToMatrix(mat4 matrix)
    {
        camera = matrix;
    }
    void PanMatrix()
    {
        //modify matrix params
        position = ...
        CalculateNewMatrix();
    }
    void CalculateNewMatrix()
    {
        //calculat new matrix;
        camera = translate(camera, position)
        ...
        //at this point I want model.matrix to be updated
    }
    glm.mat4 GetMatrix()
    {
        return camera;
    }
}
class App
{
    void Start()
    {
        Model aModel = new Model();
        InterfaceControll interface = new InterfaceControll(aModel);
        MouseControll interface = new MouseControll(aModel);
        //register mouse controll with mouse events
        //register interface control with button events
    }
}

使值类型保持同步、依赖项属性、引用、事件或重新设计

这里的主要关注点是你对 C# pass-by-* 语义的理解。使用 C#,所有参数都是按值传递的,而不是按引用传递的,碰巧引用类型的是它的内存位置,因此传递的值始终指向引用类型的同一实例。我假设您希望能够传递您的值类型,并且所有消费者都始终意识到它的变化?

我认为对此的最佳设计是使用容器引用类型,例如,在您的情况下,可能是这样的:

class GlmParameters
{
    public glm.mat4 position { get; set; }
}

或者也许只是传递您的Model类型,因为这实际上是它已经是:

class MatrixModifier
{
    private Model _model;
    void BindToMatrix(Model model)
    {
        _model = model;
    }
    void PanMatrix()
    {
        _model.position = //
        CalculateNewMatrix();
    }
    void CalculateNewMatrix()
    {
        translate(_model);
    }
}

要考虑的另一个副作用是,由于按值传递语义,理想情况下值类型应该是不可变的:

struct MyImmutableStruct
{
    private readonly int _value;
    public MyImmutableStruct(int value)
    {
        _value = value;
    }
    public int Value { get { return _value; } }
}

让我们看看这个实际操作:

var first = new MyImmutableStruct(1);
var second = first;
Console.WriteLine(first.Value);     // Prints 1
Console.WriteLine(second.Value);    // Prints 1

与。

struct MyMutableStruct
{
    private int _value;
    public MyMutableStruct(int value)
    {
        _value = value;
    }
    public int Value { get { return _value; } set { _value = value; } }
}
var third = new MyMutableStruct(1);
var fourth = third;
// Set a new value.
fourth.Value = 2;
Console.WriteLine(third.Value);     // Still prints 1
Console.WriteLine(fourth.Value);    // Prints 2

您会注意到,由于fourththird的副本,因此它不是同一个实例,因此不会反映对fourth实例的任何更改。当然,您可以通过改用引用类型或在传递值舍入时使用ref参数来解决此问题。