Почему я должен дважды определить коммутативный оператор?

Интересно, нужно ли мне дважды определить коммутативный оператор (например, *)!

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 об умножении Vector и Matrix был хорошим тогда и только тогда, когда мы предполагаем, что типы операндов разные! Очевидно, что мы можем определить оператор * только один раз, чтобы выполнить умножение векторов или матриц. Поэтому я думаю, что это не ответ.

@Marc: порядок иногда важен для операторов.

Да, но это не эквивалентно порядку, иногда важно в операндах! Вышеприведенное предложение может быть использовано в случае использования оператора + до (или после) * оператора, что приведет к разным результатам. Например:

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) { ... }

Если это так, компилятор скажет нам, что тип MyClass уже определяет член с именем op_Multiply с теми же параметрами.

Теперь мы можем использовать этот оператор двумя способами: m1 * m2 или m2 * m1, и они могут иметь разные результаты, которые зависят от процедуры умножения.

Ответ 1

Порядок иногда важен для операторов, классическими примерами являются сужение (-) и деление (/). Однако он также может применяться к умножению:

Рассмотрим, например, что они являются векторами - x является вектором (2 & times; 1), а y является вектором (1 & times; 2). Если мы интерпретируем * как матричное умножение, то x * y является вектором (2 & times; 2), но y * x является вектором (1 & times; 1).

Таким образом, компилятор С# не предполагает, что бинарные операторы являются коммутативными, даже если они обычно являются (добавление (+), умножение (*) и т.д.).

Ответ 2

Вам не нужно это делать - вам нужно только это сделать, если вы хотите написать:

MyClass x = ...;

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

Если вы хотите, чтобы одна из нижних двух строк была действительной, вы можете удалить другую операционную перегрузку.

В принципе, язык С# не предполагает, что умножение является коммутативным даже в терминах задействованных типов.

Ответ 3

Для коммутативных операций вам не нужно выполнять всю вещь дважды, вы можете обратиться к исходному оператору. Например:

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

Я надеюсь, что это поможет.

Ответ 4

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.