C# 抽象类运算符重载

标签 c# inheritance operator-overloading abstract-class

我有一个抽象类 Vector,我想重载运算符 +、-、* 等。
我希望任何派生类都能够使用这些,并获得与调用对象具有相同类型的对象。
我尝试使用泛型,(简要如下),但我找不到合法的方法来做到这一点:

public static T operator +<T>( T V1, T V2) where T : Vector
{
     //some calculation
     return new T(args);
}

然后我尝试只使用基类来完成它:

    public static Vector operator+(Vector V1, Vector V2)
    {
        if (V1.Dimension != V2.Dimension)
            throw new VectorTypeException("Vector Dimensions Must Be Equal");
        double[] ArgList = new double[V1.Dimension];
        for (int i = 0; i < V1.Dimension; i++) { ArgList[i] = V1[i] + V2[i]; }

        return (Vector)Activator.CreateInstance(V1.GetType(), new object[] { ArgList});
    }

如果这个方法传入了两个子对象,它应该对它们执行操作,并返回一个具有相同继承关系的新对象。

我遇到的问题是我无法强制所有此类子类都必须具有具有适当签名的构造函数,而且我无法调用基类构造函数来创建对象。

有什么方法可以 (a) 使这些工作中的任何一个工作,或者 (b) 以另一种方式优雅地做到这一点?

最佳答案

您可以声明您的子类可以覆盖的实例级抽象方法:

public abstract class Vector
{
    protected abstract Vector Add(Vector otherVector);

    public static Vector operator +(Vector v1, Vector v2)
    {
        return v1.Add(v2);
    }
}

public class SubVector : Vector
{
    protected override Vector Add(Vector otherVector)
    {
        //do some SubVector addition
    }
}

可能会遇到一些问题,尤其是对于多个子类(SubVector 必须知道如何使用 SomeOtherSubVectorClass 添加吗?如果添加 ThirdVectorType 会怎样类?)并可能处理 null 情况。此外,确保 SubVector.Add 在涉及交换操作时与 SomeOtherSubVectorClass.Add 的行为相同。

编辑:根据您的其他评论,您可以这样:

public class Vector2D : Vector
{
    public double X { get; set; }
    public double Y { get; set; }

    protected override Vector Add(Vector otherVector)
    {
        Vector2D otherVector2D = otherVector as Vector2D;
        if (otherVector2D != null)
            return new Vector2D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y };

        Vector3D otherVector3D = otherVector as Vector3D;
        if (otherVector3D != null)
            return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = otherVector3D.Z };

        //handle other cases
    }
}


public class Vector3D : Vector
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }

    protected override Vector Add(Vector otherVector)
    {
        Vector2D otherVector2D = otherVector as Vector2D;
        if (otherVector2D != null)
            return new Vector3D() { X = this.X + otherVector2D.X, Y = this.Y + otherVector2D.Y, Z = this.Z };

        Vector3D otherVector3D = otherVector as Vector3D;
        if (otherVector3D != null)
            return new Vector3D() { X = this.X + otherVector3D.X, Y = this.Y + otherVector3D.Y, Z = this.Z + otherVector3D.Z };

        //handle other cases
    }
}

编辑x2:

鉴于您的最新评论,也许您应该只维护一个内部数组/矩阵并只进行通用矩阵数学运算。您的子类可以针对数组索引公开 X/Y/Z 属性包装器:

public class Vector
{
    protected double[] Values;
    public int Length { get { return Values.Length; } }

    public static Vector operator +(Vector v1, Vector v2)
    {
        if (v1.Length != v2.Length)
        {
            throw new VectorTypeException("Vector Dimensions Must Be Equal");
        }
        else
        {
            //perform generic matrix addition/operation
            double[] newValues = new double[v1.Length];
            for (int i = 0; i < v1.Length; i++)
            {
                newValues[i] = v1.Values[i] + v2.Values[i];
            }

            //or use some factory/service to give you a Vector2D, Vector3D, or VectorND
            return new Vector() { Values = newValues };
        }
    }
}

public class Vector2D : Vector
{
    public double X
    {
        get { return Values[0]; }
        set { Values[0] = value; }
    }
    public double Y
    {
        get { return Values[1]; }
        set { Values[1] = value; }
    }
}


public class Vector3D : Vector
{
    public double X
    {
        get { return Values[0]; }
        set { Values[0] = value; }
    }
    public double Y
    {
        get { return Values[1]; }
        set { Values[1] = value; }
    }
    public double Z
    {
        get { return Values[2]; }
        set { Values[2] = value; }
    }
}

EDITx3:根据您的最新评论,我猜您可以在每个子类上实现运算符重载,在静态方法中执行共享逻辑(比如在基本 Vector 类中),并在某处执行 switch/case 检查以提供具体子类:

    private static Vector Add(Vector v1, Vector v2)
    {
        if (v1.Length != v2.Length)
        {
            throw new VectorTypeException("Vector Dimensions Must Be Equal");
        }
        else
        {
            //perform generic matrix addition/operation
            double[] newValues = new double[v1.Length];
            for (int i = 0; i < v1.Length; i++)
            {
                newValues[i] = v1.Values[i] + v2.Values[i];
            }

            //or use some factory/service to give you a Vector2D, Vector3D, or VectorND
            switch (newValues.Length)
            {
                case 1 :
                    return new Vector1D() { Values = newValues };
                case 2 :
                    return new Vector2D() { Values = newValues };
                case 3 :
                    return new Vector3D() { Values = newValues };
                case 4 :
                    return new Vector4D() { Values = newValues };
                //... and so on
                default :
                    throw new DimensionOutOfRangeException("Do not support vectors greater than 10 dimensions");
                    //or you could just return the generic Vector which doesn't expose X,Y,Z values?
            }
        }
    }

那么你的子类将有:

    public class Vector2D
    {
        public static Vector2D operator +(Vector2D v1, Vector2D v2)
        {
            return (Vector2D)Add(v1, v2);
        }
    }

    public class Vector3D
    {
        public static Vector3D operator +(Vector3D v1, Vector3D v2)
        {
            return (Vector3D)Add(v1, v2);
        }
    }

一些重复,但我没有想到让编译器能够做到这一点的方法:

    Vector3 v1 = new Vector3(2, 2, 2);
    Vector3 v2 = new Vector3(1, 1, 1);
    var v3 = v1 + v2; //Vector3(3, 3, 3);
    Console.WriteLine(v3.X + ", " + v3.Y + ", " + v3.Z);

或其他维度:

    Vector2 v1 = new Vector2(2, 2);
    Vector2 v2 = new Vector2(1, 1);
    var v3 = v1 + v2; //Vector2(3, 3, 3);
    Console.WriteLine(v3.X + ", " + v3.Y); // no "Z" property to output!

关于C# 抽象类运算符重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11024390/

相关文章:

ios - Swift 枚举继承

c++ - 交叉转换以获得另一个被认为是糟糕设计的接口(interface)?

c++ - 编译器无法推断出要返回哪种模板类型

c++ - 以这种方式比较字符串是一种好风格吗?

C++ 模板友元运算符重载

c# - 从文件中搜索特定数据

C# 正则表达式匹配字母、数字、下划线、破折号和点

c# - 将窗口窗体的宽度设置为 100%,就像在 HTML 中一样

c# - 使用 Rhino Mocks,BackToRecord() 是否也应该清除方法被调用次数的计数?

c# - 为什么 View 模型不可能从 Entity Framework 中的模型继承