为什么我必须两次定义一个可交换运算符?

时间:2011-09-12 09:44:15

标签: c#

我想知道我是否必须两次定义一个可交换运算符(如*)!

public static MyClass operator *(int i, MyClass m)
{
    return new MyClass(i * m.Value);
}

public static MyClass operator *(MyClass m, int i)
{
    return new MyClass(m.Value * i);
}

这背后的逻辑是什么?


其他说明:亲爱的@ Marc关于向量和矩阵乘法的答案很好 当且仅当我们假设操作数类型不同时!很明显,我们只能定义*运算符一次来执行向量或矩阵乘法。 所以我认为这不是答案。

  

@Marc:订单在运营商中有时很重要。

是的,但这不等同于命令在操作数中有时很重要!如果在{{1}之前(或之后)使用+运算符,则可以使用上述句子运算符会导致不同的结果。例如:

*

假设我们已将0 + 2 * 2 != 0 * 2 + 2运算符定义为:

*

我们无法再次定义它。

public static MyClass operator *(MyClass m1, MyClass m2)
{
    return new MyClass(m1.Value * m2.Value /* or some other kind of multiplication */);
}

如果是这样,编译器会告诉我们类型public static MyClass operator *(MyClass m2, MyClass m1) { ... } 已经定义了一个名为'op_Multiply'的成员,它具有相同的参数类型。

现在,我们可以通过两种方式使用此运算符:MyClassm1 * m2,它们可能会有不同的结果,这取决于乘法过程。

4 个答案:

答案 0 :(得分:33)

顺序在运算符中有时很重要,经典的例子是subraction(-)和division(/)。但是,它也适用于乘法:

例如,考虑它们是向量 - x是(2×1)向量,y是(1×2)向量。如果我们将*解释为矩阵乘法,则x * y是(2×2)向量,但y * x是(1×1)向量。

因此,C#编译器不假设二元运算符是可交换的,即使它们通常是(加法(+),乘法(*)等等)。

答案 1 :(得分:16)

你不必这样做 - 如果你想写的话,你只需要这样做:

MyClass x = ...;

MyClass y = x * 5;
MyClass z = 5 * x;

如果您只希望底部两行的一个有效,则可以删除另一个运算符重载。

基本上,C#语言并不认为即使在涉及的类型方面,乘法也是可交换的。

答案 2 :(得分:2)

对于可交换操作,您不需要两次实现整个事物,您可以引用初始运算符。例如:

    public static Point operator *(Point p, float scalar)
    {
        return new Point(
                scalar * p.mTuple[0],
                scalar * p.mTuple[1],
                scalar * p.mTuple[2]
            );
    }

    public static Point operator *(float scalar, Point p)
    {
        return p * scalar;
    }

我希望这会有所帮助。

答案 3 :(得分:0)

class MyClass {
    private int i;
    public MyClass(int x)  {
        i=x;
    }
    public static MyClass  operator+(MyClass a , MyClass  b)  {
        return new MyClass(a.i+b.i);
    }
    public static implicit operator MyClass(int  a) {
        return new MyClass(a);
    }

    static void Main(string[] args) {
        MyClass a , b ,c ;
        a=new MyClass(2);
        b=a+4;
        c=4+a;
        Console.WriteLine("B = {0}, C = {1}",b,c);

    }

在那里,你要做的就是让编译器将int转换为MyClass实例,然后使用MyClass + MyClass方法。