简介
运算符重载是C#提供的一种特性,允许开发者为 自定义类型(类/结构体) 定义运算符的行为。
例如,可以让Vector对象支持 + 运算,而不是仅限于基本类型(int、double等)。
💡 本质:运算符重载是一个 带有operator关键字的静态方法,通过自定义方法改变运算符的操作行为。
适用范围与限制
| 特性 | 说明 |
|---|---|
| 可重载的类型 | 类(class)和结构体(struct) |
| 不可重载的类型 | 接口、枚举、委托 |
| 方法修饰符 | 必须是public static |
| 至少一个自定义类型 | 运算符的参数中至少有一个必须是用户自定义类型 |
| 不能重载的运算符 | .(成员访问)、?:(条件运算符)、new、is、as、typeof、sizeof、=,+=,-=(但可以间接重载) |
支持重载的运算符
| 分类 | 运算符 |
|---|---|
| 一元运算符 | +-!~++--truefalse |
| 二元运算符 | +-*/%&` |
| 比较运算符 | ==!=<><=>=(必须成对重载,如重载==则必须重载!=) |
| 转换运算符 | implicit(隐式转换)explicit(显式转换) |
基本语法
publicstatic返回类型operator运算符(参数列表){// 自定义逻辑}operator关键字定义运算符。参数中至少有一个是当前类/结构体。
建议返回新的对象,保持不可变性。
常见示例
重载二元运算符(+)
创建一个二维向量类:
publicstructVector{publicdoubleX{get;}publicdoubleY{get;}publicVector(doublex,doubley)=>(X,Y)=(x,y);publicstaticVectoroperator+(Vectora,Vectorb)=>newVector(a.X+b.X,a.Y+b.Y);publicoverridestringToString()=>$"({X},{Y})";}// 使用varv1=newVector(1,2);varv2=newVector(3,4);Console.WriteLine(v1+v2);// 输出: (4, 6)重载一元运算符(-)
publicstaticVectoroperator-(Vectorv)=>newVector(-v.X,-v.Y);varv=newVector(5,-3);Console.WriteLine(-v);// 输出: (-5, 3)重载比较运算符(==, !=)
比较向量是否相等:
publicstaticbooloperator==(Vectora,Vectorb)=>a.X==b.X&&a.Y==b.Y;publicstaticbooloperator!=(Vectora,Vectorb)=>!(a==b);// 建议同时重写 Equals 和 GetHashCodepublicoverrideboolEquals(object?obj)=>objisVectorv&&this==v;publicoverrideintGetHashCode()=>HashCode.Combine(X,Y);重载
==时 必须 同时重载!=。Equals和GetHashCode也要同步实现,保证一致性。
重载递增/递减运算符(++/–)
publicstaticVectoroperator++(Vectorv)=>newVector(v.X+1,v.Y+1);publicstaticVectoroperator--(Vectorv)=>newVector(v.X-1,v.Y-1);转换运算符(implicit/explicit)
在Vector和double之间转换:
publicstaticimplicitoperatordouble(Vectorv)=>Math.Sqrt(v.X*v.X+v.Y*v.Y);// 隐式转换为长度publicstaticexplicitoperatorVector(doubled)=>newVector(d,d);// 需要强制转换使用:
Vectorv=newVector(3,4);doublelen=v;// 隐式转换Vectorv2=(Vector)5.0;// 显式转换逻辑运算符(true/false)
用于自定义布尔逻辑:
publicstaticbooloperatortrue(Vectorv)=>v.X!=0||v.Y!=0;publicstaticbooloperatorfalse(Vectorv)=>v.X==0&&v.Y==0;Vectorv=newVector(0,0);if(v)// 自动调用 operator trueConsole.WriteLine("非零向量");elseConsole.WriteLine("零向量");运算符与方法的关系
运算符重载只是语法糖,编译器会将运算符转换为静态方法调用:
varc=a+b;// 等价于varc=Vector.op_Addition(a,b);常用方法映射:
| 运算符 | 生成的方法名 |
|---|---|
+ | op_Addition |
- | op_Subtraction |
* | op_Multiply |
/ | op_Division |
== | op_Equality |
!= | op_Inequality |
综合示例:复数类
publicstructComplex{publicdoubleReal{get;}publicdoubleImag{get;}publicComplex(doublereal,doubleimag)=>(Real,Imag)=(real,imag);publicstaticComplexoperator+(Complexa,Complexb)=>newComplex(a.Real+b.Real,a.Imag+b.Imag);publicstaticComplexoperator-(Complexa,Complexb)=>newComplex(a.Real-b.Real,a.Imag-b.Imag);publicstaticComplexoperator*(Complexa,Complexb)=>newComplex(a.Real*b.Real-a.Imag*b.Imag,a.Real*b.Imag+a.Imag*b.Real);publicstaticbooloperator==(Complexa,Complexb)=>a.Real==b.Real&&a.Imag==b.Imag;publicstaticbooloperator!=(Complexa,Complexb)=>!(a==b);publicoverridestringToString()=>$"{Real}+{Imag}i";}总结
| 特性 | 说明 |
|---|---|
| 适用场景 | 数学计算类(向量、矩阵、复数)、日期时间、坐标类 |
| 关键规则 | public static、至少一个参数为自定义类型 |
| 搭配使用 | Equals、GetHashCode、IComparable |
| 设计建议 | 遵循语义一致性、返回新对象、与方法重载保持协调 |