C# 运算符重载 --- 示例

下面是 Vector 的定义, 包含只读属性, 构造函数和重写的 ToString() 方法, 最后是运算重载符

struct Vector
{
    public Vector(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public Vector(Vector v)
    {
        X = v.X;
        Y = v.Y;
        Z = v.Z;
    }

    public double X {get;}
    public double Y {get;}
    public double Z {get;}

    public override string ToString()
    {
        return string.Format("({0},{1},{2})", X, Y, Z);
    }
    
    // core
    public static Vector operator + (Vector left, Vector right)
    {
        returen new Vector(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
    }
}

看下面的代码,分析一下运算符重载这一块:

public static Vector operator + (Vector left, Vector right)
{
    returen new Vector(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
}

运算符重载的声明方式与静态方式基本相同,但 operator 关键字告诉编译器,它实际上是一个自定义的运算符重载,后面的相关运算符的实际符号, 在本例中就是 "+" ,返回类型是在使用这个运算符时获得的类型。

在本例中,把两个矢量加起来会得到另一个矢量, 所以返回类型也是 Vector。对于这个特定的 "+" 运算符重载,返回类型与包含的类一样,但并不一定是这种情况,在本例中稍候将会看到。 两个参数就是要操作的对象。 对于二元运算符(带两个参数) 如 "+" "-" 运算符,第一个参数是运算符左边的值, 第二个参数是右边的值。

C# 要求所有的运算符重载都声明为 public 和 static , 这表示它们与其类或结构相关联, 而不是与某个特定实例相关联,所有运算符重载的代码体不能访问非静态类成员, 也不能访问 this标示符;

下面编写一个简单的代码来测试一下:

void Main()
{
    Vector vect1, vect2,  vect3;
    vect1 = new Vector(3.0, 3.0, 1.0);
    vect2 = new Vector(2.0, -4.0, -4.0);
    vect3 = vect1 + vect2;
    
    Console.WriteLine("vect1 = " + vect1);
    Console.WriteLine("vect2 = " + vect2);
    Console.WriteLine("vect3 = " + vect3);
}

// 输出结果
vect1 = ( 3.0, 3.0, 1.0 )
vect2 = ( 2.0, -4.0, -4.0 )
vect3 = ( 5.0, -1.0, -3.0 )

矢量除了可以相加之外, 还可以相乘, 相减和比较它们的值。 

写个相乘的运算符重载的例子:
 

struct Vector
{
    public Vector(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public Vector(Vector v)
    {
        X = v.X;
        Y = v.Y;
        Z = v.Z;
    }

    public double X {get;}
    public double Y {get;}
    public double Z {get;}

    public override string ToString()
    {
        return string.Format("({0},{1},{2})", X, Y, Z);
    }
    
    
    public static Vector operator + (Vector left, Vector right)
    {
        returen new Vector(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
    }

    // core
    public static Vector operator * (double left, Vector right)
    {
        returen new Vector(left * right.X, left * right.Y, left * right.Z);
    }
}

矢量乘以标量意味着矢量的每个组成元素分别于标量相乘, 例如 2x(1.0, 2.5, 2.0) 就等于 (2.0, 5.0, 4.0) 。

这上面这个例子中,虽然重载了 * 运算符但是这还不够,看下面的调用例子:
 

// 假设 a 和 b 都是 Vector 类型

b = 2 * a;  // 这样运行时可以的对吧

上面的例子固然是没问题的,但是我们把他们的位置替换一下呢? 


b = a * 2;  // 这样呢?

编译器会隐式的把整数2 转换为 double类型, 用来匹配运算符重载的签名, 但是不能编译上面的代码。 编译器处理运算符重载的方式与方法重载是一样的。 它会找到与之最匹配的重载方式。 上面的语句要求第一个是Vector类型的参数, 第二个是 double类型的参数, 而我们没有提供这样一个重载。 所以编译器不能交换参数的顺序,就会抛出一个错误。 这就需要我们显示的定义一个运算符重载。 看例子:

struct Vector
{
    public Vector(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public Vector(Vector v)
    {
        X = v.X;
        Y = v.Y;
        Z = v.Z;
    }

    public double X {get;}
    public double Y {get;}
    public double Z {get;}

    public override string ToString()
    {
        return string.Format("({0},{1},{2})", X, Y, Z);
    }
    
    
    public static Vector operator + (Vector left, Vector right)
    {
        returen new Vector(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
    }

    public static Vector operator * (double left, Vector right)
    {
        returen new Vector(left * right.X, left * right.Y, left * right.Z);
    }

    // core
    public static Vector operator * (Vector left, double right)
    {
        returen new Vector(right * left.X, right * left.Y, right * left.Z);
    }
}

当我们有了符合匹配的重载, 编译器才能够正确的执行。

注意:运算符重载,必须声明为 public  static 然后要加关键字  operator 。运算符重载的代码体不能访问非静态类成员, 也不能访问 this标示符。

你可能感兴趣的:(c#)