我有多个结构如下:Vector2,Vector3,Vector4。每个结构都具有为基本算术运算以及隐式和显式转换定义的运算符重载。
到目前为止,我已在Vector4类中添加了所有可能的组合:
public static Vector4 operator + (Vector4 v1, Vector4 v2) { return (new Vector4(...)); }
public static Vector4 operator + (Vector4 v1, Vector3 v2) { return (new Vector4(...)); }
public static Vector4 operator + (Vector3 v1, Vector4 v2) { return (new Vector4(...)); }
public static implicit operator Vector4 (Vector2 v) { return (new Vector4(v)); }
public static implicit operator Vector4 (Vector3 v) { return (new Vector4(v)); }
public static explicit operator Vector3 (Vector4 v) { return (new Vector3(v)); }
public static explicit operator Vector2 (Vector4 v) { return (new Vector2(v)); }
是否有关于哪个运算符更适合哪个结构的指南?无论如何,我无法想象会损害性能,但是如果他们遇到这些代码,我有兴趣知道对其他开发人员来说会更直观。操作员组合的数量很快就会达到数十个。
顺便说一下,在其他类中复制这些运算符不会导致编译时错误。我没有检查哪个实现会被调用,但除此之外还有。
答案 0 :(得分:1)
如果每个类代表二维,三维和四维向量,我认为应该可以在某种程度上减少代码。这是因为只要你有必要的隐式向上转换,不同维度的向量之间的向量算术的定义就是多余的。因此,不需要像以下那样的运营商:
public static Vector4 operator + (Vector4 v1, Vector3 v2) { return (new Vector4(...)); }
public static Vector4 operator + (Vector3 v1, Vector4 v2) { return (new Vector4(...)); }
我还建议让较低维度的向量处理更高维度向量的向上转换和向下转换。这是因为下转换信息,以及如何做的选择应该在"更有限的"结构
因此,VectorI
结构需要对所有VectorI+J
进行隐式向上转换,并向所有VectorI-J
结构显式向下转换。另外,VectorI结构需要实现自己的向量算法。但是因为'我'只有值2,3和4,这意味着:
Vector2需要对Vector3和Vector4进行隐式转换,以及从Vector3和Vector4进行显式向下转换。
Vector3需要对Vector4进行隐式转换,以及从Vector4进行显式向下转换。
Vector4无需转换。
所有4个结构只为相同维度的向量之间的自身实现线性代数方法。
我刚刚测试了这个方案并添加了不同的Vector2,Vector3和Vector4结构,并且正在进行隐式转换。
<强>更新强>
刚刚添加了一个快速原型实现,并且所有跨维度添加都按预期工作:
public struct Vector2
{
public double x, y;
public Vector2(double x, double y)
{
this.x = x; this.y = y;
}
#region linear algebra
public static Vector2 operator +(Vector2 first, Vector2 second)
{
return new Vector2(first.x + second.x, first.y + second.y);
}
#endregion
#region conversions to/from higher dimensions
public static implicit operator Vector3(Vector2 v2)
{
return new Vector3(v2.x, v2.y, 0);
}
public static implicit operator Vector4(Vector2 v2)
{
return new Vector4(v2.x, v2.y, 0, 0);
}
public static explicit operator Vector2(Vector3 v3)
{
return new Vector2(v3.x, v3.y);
}
public static explicit operator Vector2(Vector4 v4)
{
return new Vector2(v4.x, v4.y);
}
#endregion
}
public struct Vector3
{
public double x, y, z;
public Vector3(double x, double y, double z)
{
this.x = x; this.y = y; this.z = z;
}
#region linear algebra
public static Vector3 operator +(Vector3 first, Vector3 second)
{
return new Vector3(first.x + second.x, first.y + second.y, first.z + second.z);
}
#endregion
#region conversions to/from higher dimensions
public static implicit operator Vector4(Vector3 v3)
{
return new Vector4(v3.x, v3.y, v3.z, 0);
}
public static explicit operator Vector3(Vector4 v4)
{
return new Vector3(v4.x, v4.y, v4.z);
}
#endregion
}
public struct Vector4
{
public double x, y, z, w;
public Vector4(double x, double y, double z, double w)
{
this.x = x; this.y = y; this.z = z; this.w = w;
}
#region linear algebra
public static Vector4 operator +(Vector4 first, Vector4 second)
{
return new Vector4(first.x + second.x, first.y + second.y, first.z + second.z, first.w + second.w);
}
#endregion
}
以下测试代码可以正常工作:
public static class VectorHelper
{
public static void Test()
{
var v2 = new Vector2(5, 5);
var v3 = new Vector3(7, 7, 7);
var v4 = new Vector4(3, 3, 3, 3);
var res1 = v2 + v3;
Debug.Assert(res1.GetType().Name == "Vector3"); // No assert
var res2 = v3 + v4;
Debug.Assert(res2.GetType().Name == "Vector4"); // No assert
var res3 = v2 + v4;
Debug.Assert(res3.GetType().Name == "Vector4"); // No assert
Debug.Assert(res3.x == 8 && res3.y == 8 && res3.z == 3 && res3.w == 3); // No assert
}
}