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

C# 泛型类的隐式转换仅限于某些类型,c#,.net,generics,implicit-conversion,C#,.net,Generics,Implicit Conversion,假设我们对泛型类Matrix有想法,其中T是数字类型(Complex或double或float,int等) 很自然,我们在C语言中有隐式转换,从float到double,从double到Complex。一般规则是,我们有从较小类型到较大类型的隐式转换。到目前为止还不错 现在假设我们正在实现我们的矩阵类型。由于这种新类型在某种程度上也是数值类型(或者至少它包含数值),因此自然会有从矩阵到矩阵的隐式转换,从矩阵到矩阵等。至少对于乘法等数学运算来说,有这些隐式转换是很好的,然而,这似乎不可能正确实现,

假设我们对泛型类
Matrix
有想法,其中
T
是数字类型(
Complex
double
float
int
等)

很自然,我们在C语言中有隐式转换,从
float
double
,从
double
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();
    }
}
公共抽象部分类矩阵
{
/// 
///隐式地将矩阵转换为双精度复数。
/// 
公共静态隐式算子矩阵(矩阵)
{
matrix.ToComplex();
}
/// 
///隐式地将矩阵转换为双精度实数。
/// 
公共静态隐式算子矩阵(矩阵)
{
矩阵ToDouble();
}
}
它不会编译,因为“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();
    }
}
公共抽象部分类矩阵
{
/// 
///隐式地将矩阵转换为单精度实数。
/// 
公共静态隐式算子矩阵(矩阵)
{
矩阵ToDouble();
}
}
有没有办法实现这件事,感觉很自然,所以我认为这应该是可以实现的

目前,我已经创建了一个解决方案,它支持所有类型到最大类型的隐式转换,但不能解决从
矩阵
矩阵
的转换,它只解决到
矩阵
的转换

公共抽象部分类矩阵
{
/// 
///隐式地将矩阵转换为双精度复数。
/// 
公共静态隐式算子矩阵(矩阵)
{
返回矩阵.Map(x=>
{
if(x是数字复数32)
{
var xc32=(Numerics.Complex32)(object)x;
返回新的Complex64(xc32.Real,xc32.virtual);
}
返回新的Complex64(Convert.ToDouble(x),0);
},0.AllowSkip);
}
}
如果有人对这个问题的背景感兴趣,你可以看看


解决这个问题的另一个选择是使用类似“扩展运算符”(类似于扩展方法)的东西,但这些在C#中不存在。

首先,我不确定将泛型与数字基元类型一起使用是否是一个好方法。这是语言中一个非常严重的缺失方面,似乎没有任何计划在短时间内解决它。阅读更多信息

  • 没有数字约束,最好是
    struct
    ,这很糟糕
  • 对于任何算术支持(如果您要实现矩阵,这是必须的),您需要定义一个带有
    Add
    Multiply
    等功能的
    IArithmetic
    接口,并且您将到处装箱和拆箱,这可能会对性能产生很大影响

    你的代码远比这糟糕;因为您似乎缺少
    T
    的通用接口,所以您需要强制转换到对象以使通用强制转换成功

    另外,如果您没有类似于
    if(typeof(t)==typeof(Complex))…
    的公共接口代码,那么当使用泛型时,这是一个很大的危险信号;泛型类/方法应该处理无限多的类型,而不仅仅是几个预设类型,这就是泛型的含义

  • 我认为你应该后退一步,重新考虑你的方法。当语言类型系统似乎在与你作对而没有任何帮助时,这肯定表明你做错了什么

    为什么不简单地实现一个最大类型的非泛型矩阵呢?复数的矩阵。有一个浮动矩阵或双浮动矩阵的好处是什么?它不可能是性能或内存效率,因为任何非通用的解决方案都会比当前的方法更好,因为所有的装箱都在进行中

    更新:在浏览了您所基于的库之后,我不确定您为什么不使用
    Matrix
    作为基本类型

    public class DoubleMatrix : Matrix<double>
    {
        //now this is legal
        public static implicit operator DoubleMatrix(FloatMatrix matrix)
            => matrix.ToDouble();
    }
    
    公共类双矩阵:矩阵
    {
    //现在这是合法的
    公共静态隐式运算符DoubleMatrix(FloatMatrix)
    =>matrix.ToDouble();
    }
    

    其中
    FloatMatrix
    显然是
    FloatMatrix:Matrix
    我所知道的创建通用向量或矩阵类并让它执行代数(加法、减法、乘法)的唯一方法是发出调用运算符的
    MSIL
    代码(例如
    运算符+
    )。然后,它可以与任何定义了
    静态MyType操作符+(MyType a、MyType b)
    的类型以及内置类型一起使用

    有关更多详细信息,请参阅类似问题

    使用
    操作中的静态方法,您可以获得以下示例代码

    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
    }
    
    公共类矩阵
    {
    T[,]元素;
    静态只读Func add=Operation.add;
    公共静态矩阵运算器
    
    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
    }