这是使用算术实现多态性的好方法吗?

Is this a good way to implement polymorphism for using arithmetic?

所以我想使用多态性来使用算术。

因此,我的第一个想法是制作一个使用算术、IAddable 等的接口;但是我在互联网上发现这是不可能的。但是我想到了一个技巧,现在我想知道:这是多态性的一个很好且快速的实现吗?

    public abstract class RingElement
    {
        public static RingElement operator +(RingElement e1, RingElement e2)
        {
            if (e1 == null)
                return e2;
            if (e2 == null)
                return e1;
            Type type = e1.GetType();
            return (RingElement) type.GetMethod("op_Addition").Invoke(null, new object[] {e1, e2 });
        }

        public static RingElement operator *(RingElement e1, RingElement e2)
        {
            if (e1 == null)
                return e2;
            if (e2 == null)
                return e1;
            Type type = e1.GetType();
            return (RingElement) type.GetMethod("op_Multiply").Invoke(null, new object[] { e1, e2 });
        }
    }

我制作了两个 RingElements:一个 doubleElement(只包含一个 double)和一个通用的 Matrix<T> : RingElement where T : RingElement 空值处理是为了实现空金额或空产品的可能性。

RingElement 的每个继承 class 都应该有两个静态方法 public static T operator +(T x, T y) public static T operator *(T x, T y)

有自己的实现体,其中 T 是 class 类型

你来的有点早))。 c# 9 (link) 中有 Type Classes 个候选者,这可能是 c# 中最优雅的解决方案。

(如果使用f#是一个选项,它已经有Statically Resolved Type Parameters,而这个link下的页面正好显示了算术多态的例子)

这行得通,使用反射的位就可以了。它不是 type-safe 并且可能不是最高效的方法,但不幸的是,对于您在 C# 中的问题还没有真正完全令人满意的答案。

以下是一些您可能会觉得有用的建议:

为了解决 Scott Hannen 的合理担忧,关于能够将 DogRingElement : RingElement 添加到 CatRingElement : RingElement,您可以使用奇怪的重复模式,

public abstract class RingElement<T> where T : RingElement<T> { .. }

public class DogRingElement : RingElement<DogRingElement> { .. }
public class CatRingElement : RingElement<CatRingElement> { .. }

为了提高性能,您可以尝试,

public static RingElement operator +(RingElement e1, RingElement e2)
{
    return (RingElement) ((dynamic) e1 + (dynamic) e2);
}

这在开始时对性能有一定的影响,但在第一次使用后会变得更快。

您可以在 Matrix 实现中使用 dynamic 变量,

class Matrix<T>
{
     public static Matrix<T> operator + (Matrix<T> a, Matrix<T> b)
     {
         // check a.M = b.M, a.N = b.N
         var c = new Matrix<T>(a.M, a.N);
         for (var i = 0; i < a.N ; i ++)
         {
             for (var i = 0; i < a.N ; i ++)
             {
                  dynamic x = a[i, j], y = b[i, j];
                  c[i,j] = (T) (x + y);
             }
         }
         return c;
    }
}

第一次使用性能不是很好,后来就下降了。

您还可以考虑一个实现算术运算符的包装器 class,持有对实现具有 Add、Mult 等方法的接口的对象的引用,

public interface IRingElem<T>   // strangely recurring pattern
     where T : IRingElem<T>
{
    T Add(T);
}

public class Num<T>
     where T : IRingElem<T>
{
    private readonly T elem;

    public static Num<T> operator + (Num<T> a, Num<T> b)
    {
        return new Num<T>(a.elem.Add(b.elem));
    }

}

通过实现从 TNum<T> 的显式转换和从 Num<T>T 的隐式转换,这相当方便。

如果您追求真正好的性能,您可以考虑将包装器 class 设为 struct(删除 readonly 有时也有帮助)并在任何地方使用 [MethodImpl(MethodImplOptions.AggressiveInlining)]包装器 class.