为什么我必须两次定义一个可交换运算符?
我想知道我是否必须两次定义一个可交换运算符(如*
)!
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:订单在运营商中有时很重要。
是的,但这不等同于Order在操作数中有时很重要! 如果在*
运算符之前(或之后)使用+
运算符,则可以使用上述句子,这将导致不同的结果。 例如:
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
,它们可能具有不同的结果,这取决于乘法过程。
顺序有时在运算符中很重要,经典的例子是减法( -
)和除法( /
)。 但是,它也适用于乘法:
例如,考虑它们是向量 – x
是(2×1)向量, y
是(1×2)向量。 如果我们将*
解释为矩阵乘法,则x * y
是(2×2)向量,但是y * x
是(1×1)向量。
因此,C#编译器不会假设二元运算符是可交换的,即使它们通常是(加法( +
),乘法( *
)等)。
您不必这样做 – 如果您想要能够写,您只需要这样做:
MyClass x = ...; MyClass y = x * 5; MyClass z = 5 * x;
如果您只希望底部两行中的一行有效,则可以删除其他运算符重载。
基本上,C#语言并不假设即使在涉及的类型方面,乘法也是可交换的。
对于可交换操作,您不需要实现整个事物两次,您可以引用初始运算符。 例如:
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; }
我希望这个对你有用。
class MyClass { private int i; public MyClass(int x) { i=x; } public static MyClass operator+(MyClass a , MyClass b) { return new MyClass(a.i+bi); } 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方法。