泛型类的隐式转换仅限于某些类型

Paw*_*oka 5 .net c# generics implicit-conversion

假设我们有一个泛型类的想法Matrix<T>哪里T是数字型(Complexdouble或者float,int等).

很自然,我们在C#中从in floatdoublefrom double进行了隐式转换Complex.一般规则是我们有从较小类型到较大类型的隐式转换.到现在为止还挺好.

现在假设我们正在实现我们的Matrix<T>类型.由于这种新型的方式是数字也(或者至少其持有的数值),这是很自然有隐式转换从Matrix<float>Matrix<double>,从Matrix<double>Matrix<Complex>等至少它是好的,有这些像乘数学运算,加等但是这似乎无法正确实现,因为隐式运算符要求至少一个类型与我们实现它的类相同.

示例:下面的代码无法编译,甚至认为它可以解决我的问题.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

它不会编译,因为"CS0556用户定义的转换必须转换为封闭类型或从封闭类型转换",让我说我很好,因为它是语言规范的一部分,但不应该有任何其他方法来实现这一点?

例如,这也不编译.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法实现这个目标,感觉很自然,所以我觉得它应该是可以实现的?

目前我已经创建了一种解决方法,可以将所有类型的隐式转换转换为最大类型,但不能解析转换Matrix<float>为转换Matrix<double>,它只会将转换解析为Matrix<Complex>.

public abstract partial class Matrix<T>
{
    /// <summary>
    /// Implicitly converts a matrix to double precision complex numbers.
    /// </summary>
    public static implicit operator Matrix<Complex64>(Matrix<T> matrix)
    {
        return matrix.Map(x =>
        {
            if (x is Numerics.Complex32)
            {
                var xc32 = (Numerics.Complex32)(object)x;
                return new Complex64(xc32.Real, xc32.Imaginary);
            }
            return new Complex64(Convert.ToDouble(x), 0);
        }, Zeros.AllowSkip);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果有人对这个问题的背景感兴趣,你可以看看 https://github.com/mathnet/mathnet-numerics/issues/304

解决这个问题的另一个选择可能是使用"扩展运算符"(类似于扩展方法),但C#中不存在这些选项.

InB*_*een 1

首先,我不太确定将泛型与数字基元类型一起使用是一个好的选择。这是该语言的一个非常严重的缺陷,并且似乎没有任何计划在短时间内解决它。阅读此答案以获取更多信息。

  1. 没有数字限制,你能做的最好的事情就是struct这是非常糟糕的。
  2. 对于任何算术支持(如果您要实现矩阵,这是必须的),您需要使用 等定义一个IArithmetic接口AddMultiply并且您将在各处进行装箱和拆箱,这可能会对性能产生很大影响。

    你的代码比那更糟糕;因为您似乎缺少一个通用接口,因为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();
}
Run Code Online (Sandbox Code Playgroud)

FloatMatrix明明是哪里啊FloatMatrix: Matrix<Float>