C# 运算符重载方法 C#如何对运算符进行重载

来源:这里教程网 时间:2026-02-21 17:41:18 作者:

运算符重载在 C# 中只能在

struct
class
内部用
public static
方法实现,且必须使用
operator
关键字声明;不能重载所有运算符,也不能改变运算符优先级或结合性。

哪些运算符可以重载

C# 允许重载的运算符有明确限制。可重载的包括:

一元运算符:
+
-
!
~
++
--
true
false
二元运算符:
+
-
*
/
%
&
|
^
、<code>>>
==
!=
、<code>>
、<code>>=
必须成对重载:
==
!=
 和 <code>>
 和 <code>>=
true
false

不可重载的包括:

&&
||
?:
=
.
?:
->
sizeof
typeof
new
checked
unchecked
等。

重载
==
!=
的正确写法

这是最容易出错的地方:重载

==
后,编译器会强制要求同时重载
!=
,并且还必须重写
Equals(object)
GetHashCode()
,否则会触发 CS0660 / CS0661 警告。

典型错误是只重载

==
,或在
==
中直接调用
object.ReferenceEquals
但没处理
null
参数。

public class Vector2
{
    public double X { get; }
    public double Y { get; }
<pre class='brush:php;toolbar:false;'>public Vector2(double x, double y) => (X, Y) = (x, y);
public static bool operator ==(Vector2 a, Vector2 b)
{
    if (ReferenceEquals(a, b)) return true;
    if (a is null || b is null) return false;
    return a.X == b.X && a.Y == b.Y;
}
public static bool operator !=(Vector2 a, Vector2 b) => !(a == b);
public override bool Equals(object obj) => obj is Vector2 v && this == v;
public override int GetHashCode() => HashCode.Combine(X, Y);

}

重载
+
运算符并支持混合类型

如果希望

Vector2 + double
也能工作,不能只写
Vector2 + Vector2
;需额外提供参数类型不同的重载版本。但要注意隐式转换可能引发歧义。

推荐显式提供
Vector2 + double
double + Vector2
两个版本(后者因交换律必要)
避免定义
implicit operator double(Vector2)
,否则
vector + 1.0
可能被误解释为
(double)vector + 1.0
返回新实例而非修改原对象(符合值语义直觉)
public static Vector2 operator +(Vector2 a, Vector2 b) =>
    new Vector2(a.X + b.X, a.Y + b.Y);
<p>public static Vector2 operator +(Vector2 v, double s) =>
new Vector2(v.X + s, v.Y + s);</p><p>public static Vector2 operator +(double s, Vector2 v) =>
new Vector2(v.X + s, v.Y + s);

为什么重载
++
要返回新对象而不是
this

因为

++
是一元后缀/前缀运算符,C# 要求其返回值参与表达式计算。若返回
this
并修改内部状态,会导致与内置数值类型行为不一致(如
int
++
返回副本),也破坏不可变设计意图。

更关键的是:如果

++
修改自身又返回
this
,则
v1 = v2++;
会让
v1
v2
引用同一对象,后续修改
v2
会意外影响
v1
—— 这在结构体中还会因装箱引发更隐蔽问题。

所以标准做法是:

前缀
++
:创建新实例,返回新实例
后缀
++
:先保存当前状态,再创建新实例,返回保存的旧状态
public static Vector2 operator ++(Vector2 v) => new Vector2(v.X + 1, v.Y + 1);
<p>// 后缀版本需手动模拟(C# 不自动区分,靠方法签名)
public static Vector2 operator ++(ref Vector2 v)
{
var old = v;
v = new Vector2(v.X + 1, v.Y + 1);
return old;
}

注意:C# 实际不支持

ref
形参用于运算符重载(上述写法非法),真正合规的后缀
++
必须返回旧值副本,且不能修改原对象 —— 所以多数场景下应避免重载
++
,改用明确的
Increment()
方法。

相关推荐