Почему я должен дважды определить коммутативный оператор?
Интересно, нужно ли мне дважды определить коммутативный оператор (например, *
)!
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.