假设我们知道通用类Matrix<T>
,其中T
是数字类型(Complex
或double
或float
,int
等)
我们在C#中从float
到double
,从double
到Complex
进行隐式转换是很自然的。一般规则是我们有从较小类型到较大类型的隐式转换。到目前为止一切都很好。
现在假设我们正在实施Matrix<T>
类型。由于这种新类型在某种程度上也是数字(或者至少它包含数值),因此从Matrix<float>
到Matrix<double>
进行隐式转换是很自然的,从Matrix<double>
到{{1至少将它们用于数学运算,如乘法,加法等是很好的。但是这似乎不可能正确实现,因为隐式运算符要求至少一个类型与我们实现它的类相同。
示例:下面的代码无法编译,甚至认为它可以解决我的问题。
Matrix<Complex>
它不会编译,因为“CS0556用户定义的转换必须转换为封闭类型或从封闭类型转换”,让我说我很好,因为它是语言规范的一部分,但不应该有任何其他方式实现这个目标?
例如,这不会编译。
public abstract partial class Matrix<T>
{
/// <summary>
/// Implicitly converts a matrix to double precision complex numbers.
/// </summary>
public static implicit operator Matrix<Complex64>(Matrix<double> matrix)
{
matrix.ToComplex();
}
/// <summary>
/// Implicitly converts a matrix to double precision real numbers.
/// </summary>
public static implicit operator Matrix<double>(Matrix<float> matrix)
{
matrix.ToDouble();
}
}
有没有办法实现这个目标,感觉很自然,所以我认为它应该是可以实现的?
目前我已经创建了一种解决方法,可以将所有类型的隐式转换转换为最大类型,但不能解决从public abstract partial class Matrix<double>
{
/// <summary>
/// Implicitly converts a matrix to single precision real numbers.
/// </summary>
public static implicit operator Matrix<double>(Matrix<float> matrix)
{
matrix.ToDouble();
}
}
到Matrix<float>
的转换,它只会将转换解析为Matrix<double>
Matrix<Complex>
如果有人对此问题的背景感兴趣,您可以查看https://github.com/mathnet/mathnet-numerics/issues/304
解决此问题的另一个选择可能是使用“扩展运算符”(类似于扩展方法),但C#中不存在这些选项。
答案 0 :(得分:0)
首先,我不确定使用带有数字基元类型的泛型是一条很好的道路。这是一个相当严重缺乏语言的方面,并且似乎没有任何计划在短时间内解决它。请阅读this SO answer了解详情。
struct
,这非常糟糕。对于任何算术支持,如果您要实现矩阵,则必须使用IArithmetic
,Add
等来定义Multiply
接口。 #39;将在整个地方进行装箱和拆箱,这可能会对性能产生重大影响。
你的代码远不如此;因为你似乎缺少T
的通用接口,你需要转换为对象以使通用转换成功。
此外,如果您没有开始出现类似于if (typeof(T) == typeof(Complex)) ...
的通用界面代码,那么在使用泛型时这是一个很大的危险信号;泛型类/方法应该在无限种类型上工作,而不仅仅是几种预设类型,这就是泛型的含义。
我认为你应该退后一步,重新思考你的方法。当语言类型系统似乎在与你作斗争并且没有任何帮助时,这肯定表明你做错了。
为什么不简单地实现最大类型的非通用矩阵?复数矩阵。拥有浮动或双打矩阵有什么好处?它不具备性能或内存效率,因为任何非通用解决方案都会比您当前的方法更好,所有装箱都会进行拆箱。
更新:浏览完您所依据的库时,我不确定您为什么不首先使用Matrix<T>
作为基础类型。
public class DoubleMatrix : Matrix<double>
{
//now this is legal
public static implicit operator DoubleMatrix(FloatMatrix matrix)
=> matrix.ToDouble();
}
FloatMatrix
显然是FloatMatrix: Matrix<Float>
。
答案 1 :(得分:0)
我知道创建一个通用向量或矩阵类并让它进行代数(加法,减法,乘法)的唯一方法是发出调用运算符的MSIL
代码(例如operator +
) 。然后它可以与定义了static MyType operator + (MyType a, MyTYpe b)
的任何类型以及内置类型一起使用。
有关详细信息,请参阅this answer of mine类似问题。
使用Operation<T>
中的静态方法,您可以使用以下示例代码
public class Matrix<T>
{
T[,] elements;
static readonly Func<T,T> add = Operation<T>.Add;
public static Matrix<T> operator + (Matrix<T> A, Matrix<T> B)
{
Matrix<T> result = new Matrix<T>(rows,cols);
for(int i=0; i<rows; i++)
{
for(int j=0; j<cols; j++)
{
result[i,j] = add(A[i,j], B[i,j]);
}
}
return result;
}
// rest of algebra
}
因此,如果您确定了定义了Complex64
的{{1}}类,则可以声明operator +
并直接执行Matrix<Complex64>
之类的代数。运行时将为内置类型或自定义类型调用适当的运算符。速度影响很小,因为找到适当的调用方法的反射只在首次使用时按类型完成一次