gpt4 book ai didi

c# - 比 Unsafe.As 转换到子类更好的方法来解决我的类层次结构问题?

转载 作者:行者123 更新时间:2023-12-05 09:26:11 25 4
gpt4 key购买 nike

(我写的是关于矩阵的,但别担心,这不是一道数学题,假设你没有数学知识。)

我有一个包含三个字段的 Matrix

double[] Data;
int Rows;
int Columns;

并定义了数百种数学运算。

另外,我有一个 SymmetricMatrix : Matrix 子类,它没有自己的实例字段,它通过继承提供上述所有操作,提供一些额外的操作(如 EigenvalueDecomposition),最后 使用new 关键字重复一些 定义以将返回类型更改为SymmetricMatrix

例如,如果 Matrix

public Matrix MatrixMultiplication(Matrix otherMatrix)
public Matrix ScaledBy(double scalar)

然后 SymmetricMatrix 将简单地继承 MatrixMultiplication 但它会更改 ScaledBy 以返回 SymmetricMatrix

我没有重新实现 ScaledBy ,而是通过

定义它
// SymmetricMatrix.cs
public new SymmetricMatrix ScaledBy(double scalar) => base.ScaledBy(scalar).AsSymmetricMatrix()
// Matrix.cs
public SymmetricMatrix AsSymmetricMatrix() => Unsafe.As<SymmetricMatrix>()

(我使用 new 而不是 virtual+override 的原因与这个问题的目的无关紧要)。

我发现这种方法的效果出奇地好,它使我能够非常简洁地定义 SymmetricMatrix.cs。明显的缺点是它可能会利用不受支持的行为(?)并且它会混淆我经常使用的调试器(转换结果的运行时类型是 Matrix 这不是它的编译时类型 SymmetricMatrix,然而,在 SymmetricMatrix 上定义的所有操作都会成功,因为两个类持有的数据是相同的)

问题

  1. 您是否预见到我的方法存在任何我没有想到的问题?

  2. 我的方法是否会因下一个 dotnet 版本而中断?

  3. 您认为有更简洁的方法来实现我想要的吗?我有一些想法,但似乎没有一个能顺利解决。例如,我无法通过

    对哪些操作在父类中保留子类进行编码
class Matrix<T> where T : Matrix
...
T ScaledBy(double other)

因为操作是否保留 Child 类是只有 Child 才能拥有的知识。例如,SymmetricPositiveDefiniteMatrix 不会被 ScaledBy 保留。

或者,我可以使用封装而不是继承并定义

class BaseMatrix
{
...lots of operations
}
...
class Matrix : BaseMatrix
{
private BaseMatrix _baseMatrix;
...lots of "OperationX => new Matrix(_baseMatrix.OperationX)"
}
class SymmetricMatrix : BaseMatrix
{
private BaseMatrix _baseMatrix;
...lots of "OperationX => preserving ? new SymmetricMatrix(_baseMatrix.OperationX) : new Matrix(_baseMatrix.OperationX);"
}

虽然编写代码非常令人难过,因为我必须手动将我对 BaseMatrix 所做的每个更改传播到目前四个额外的类,并且用户必须手动转换 SymmetricMatrix 在许多场景中都可以转换为 Matrix

最后,我可以简单地不提供子类,而是使用像 bool _isSymmetric 这样的标志,并通过更改/设置我所有方法中的标志来编码保持对称性/正性/...的操作。这也很可悲,因为:

  1. 然后用户将能够编写 Matrix.EigenvalueDecomposition() 只是为了在运行时使用 进行中断 您必须向我保证您的矩阵是对称的,因为我只为这种情况实现了 EigenvalueDecomposition 错误

  2. 很容易忘记重置未保留的标志,然后意外地运行假设对称的操作(BLAS 通过简单地忽略矩阵的一半来做到这一点)

  3. 我喜欢能够在类型系统而不是注释中指定,例如,我从 CholeskyFactor 返回的矩阵是下三角矩阵(约定不同,有些人可能期望上三角矩阵矩阵)

  4. 用户看不到当前设置了哪些标志,因此他们不知道我是否使用给定算法的“专用”版本,并且可能最终使用 .SetSymmetric()为了安全,不必要到处都是。

最佳答案

除非我遗漏了一个要求,否则您可以使用泛型实现您想要的

一个(不那么简短的)例子:

public abstract class BaseMatrix<TMatrix> where TMatrix : BaseMatrix<TMatrix>
{
// Replace with how you actuallt are storing you matrix values
protected object _valueStore;

// common initialization (if required), if not keep empty
protected BaseMatrix()
{

}

// necessary to copy the value store.
protected BaseMatrix(object valueStore)
{
this._valueStore = valueStore;
}

public virtual TMatrix ScaledBy(double scalar)
{
// implementation
return default;
}
}

public class Matrix : BaseMatrix<Matrix>
{

}

public class SymmetricMatrix : BaseMatrix<SymmetricMatrix>
{
public SymmetricMatrix() : base(){}

// allows to build from another matrix, could be internal
public SymmetricMatrix(object valueStore) : base(valueStore){}

public override SymmetricMatrix ScaledBy(double scalar)
{
return base.ScaledBy(scalar);
}
}

public class SymmetricPositiveDefiniteMatrix : BaseMatrix<SymmetricPositiveDefiniteMatrix>
{
// If we *know* the type is not the same after this method call, we mask with a new one retirning the target type
// A custom cast operator will handle the conversion
public new SymmetricMatrix ScaledBy(double scalar)
{
return base.ScaledBy(scalar);
}

// Added to allow a cast between SymmetricPositiveDefiniteMatrix and SymmetricMatrix
// in this example, we keep the value store to not have to copy all the values
// Depending on project rules could be explicit instead
public static implicit operator SymmetricMatrix(SymmetricPositiveDefiniteMatrix positiveSymmetricMatrix)
{
return new SymmetricMatrix(positiveSymmetricMatrix._valueStore);
}
}

这将使 ScaledBy(double)方法在每种类型的矩阵中可用,并返回调用它的矩阵的类型。

而且它符合您的要求,不必重新定义每个类中的大多数方法/属性。

显然,您可以覆盖子类中的方法,以便在 base() 之前或之后执行更多操作调用甚至定义一个完全不同的实现。

一个缺点是如果您需要一种类型来继承自 BaseMatrix<TMatrix> 的类.您无法更改泛型类型参数。

或者,如果这真的不符合您的需求并且更喜欢走封装路线,您可以看看 source generators因为代码似乎很重复。

关于c# - 比 Unsafe.As 转换到子类更好的方法来解决我的类层次结构问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74122649/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com