You can declare abstract methods at the instance level that your subclass can override:
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) {
There may be some problems, especially with several subclasses (Will SubVector
should know how to add using SomeOtherSubVectorClass
? What if you add the ThirdVectorType
class?) And possibly handle null cases. Also, make sure SubVector.Add
behaves the same as SomeOtherSubVectorClass.Add
when it comes to commutative operations.
EDIT: based on your other comments, you could be something like:
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 };
EDITx2:
Given your last comment, maybe you should just maintain an internal array / matrix and just do the math. Your subclasses can display wrappers of X / Y / Z properties by array:
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 {
EDITx3: based on your last comment, I assume that you can implement operator overloads on each subclass, make general logic in a static method (say, in the Vector base class), and do a switch / case check somewhere to provide a specific subclass :
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? } } }
Then your subclasses will have:
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); } }
Some duplication, but I donβt see a way around it from above to allow the compiler to do this:
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);
or for other measurements:
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!