c# - 运算符重载放置和冗余

标签 c# .net operator-overloading

我有多个结构如下: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)); }

是否有关于哪些运算符更适合哪种结构的指南?我无法想象任何一种方式都会损害性能,但我很想知道如果其他开发人员遇到这段代码,他们会更直观地了解什么。运算符组合的数量迅速增加到几十种。

顺便说一句,在其他类中复制这些运算符不会导致编译时错误。我没有检查将调用哪个实现,但这不是重点。

最佳答案

如果每个类代表二维、三维和四维向量,我认为您应该可以减少一些代码。这是因为只要您具有必要的隐式上转换,不同维度的向量之间的向量算术定义 就是多余的。因此不需要像下面这样的运算符:

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 结构需要实现自己的向量算法。但由于“I”只有值 2、3 和 4,这意味着:

  1. Vector2 需要隐式转换为 Vector3 和 Vector4,以及从 Vector3 和 Vector4 显式向下转换。

  2. Vector3 需要隐式转换为 Vector4 以及从 Vector4 显式向下转换。

  3. Vector4 不需要转换。

  4. 所有 4 个结构都为它们自己实现线性代数方法,仅在相同维度的向量之间。

我刚刚测试了这个方案并添加了不同的 Vector2、Vector3 和 Vector4 结构,在完成隐式转换的情况下按预期工作。

更新

刚刚做了一个加法的快速原型(prototype)实现,所有的跨维度加法都按预期工作:

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
    }
}

关于c# - 运算符重载放置和冗余,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24793705/

相关文章:

c# - Asp .NET 下拉列表在表单提交后为空

c# - 具有空选择的 SelectList

Apple IOS 上的 C# 应用程序

c++ - 为类层次结构重载 operator== 的正确方法是什么?

c++ - Operator() 作为 Matrix 类的下标

c# - 没有类型为 'IEnumerable<SelectListItem>' 且键为 'Register.CountryId' 的 ViewData 项

c# - 加密和解密字节数组

c# - 有什么方法可以让 .NET 代码在电子邮件到达时运行和处理它们?

c# - 无法在 C# 中禁用或启用运行 Powershell 命令的 Exchange 邮箱

C++ 增量运算符重载