C# 运算符重载
C# 运算符重载
可以重定义或重载 C# 中内置的运算符。因此,程序员也可以使用用户自定义类型的运算符。重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。
例如,请看下面的函数:
public static Box operator+ (Box b, Box c) { Box box = new Box(); box.length = b.length + c.length; box.breadth = b.breadth + c.breadth; box.height = b.height + c.height; return box; }
上面的函数为用户自定义的类 Box 实现了加法运算符(+)。它把两个 Box 对象的属性相加,并返回相加后的 Box 对象。
运算符重载的实现
class User { private int fans; private int follows; public void setFans(int fan) { fans = fan; } public void setFollows(int follw) { follows = follw; } public int getDiffer() { return (fans+follows)-Math.Max(fans, follows); } //重载运算符 public static User operator+ (User ua,User ub) { User uc = new User(); uc.fans = ua.fans + ub.fans; uc.follows = ua.follows + ub.follows; return uc; } } }
Ua differ : 114514 Ub differ : 42 Uc differ : 114556
operator 关键字用于在类或结构声明中声明运算符。运算符声明可以采用下列四种形式之一:
public static result-type operator unary-operator ( op-type operand ) public static result-type operator binary-operator ( op-type operand, op-type2 operand2 ) public static implicit operator conv-type-out ( conv-type-in operand ) public static explicit operator conv-type-out ( conv-type-in operand )
参数:
- result-type 运算符的结果类型。
- unary-operator 下列运算符之一:+ - ! ~ ++ — true false
- op-type 第一个(或唯一一个)参数的类型。
- operand 第一个(或唯一一个)参数的名称。
- binary-operator 其中一个:+ - * / % & | ^ << >> == != > < >= <=
- op-type2 第二个参数的类型。
- operand2 第二个参数的名称。
- conv-type-out 类型转换运算符的目标类型。
- conv-type-in 类型转换运算符的输入类型。
注意:
前两种形式声明了用户定义的重载内置运算符的运算符。并非所有内置运算符都可以被重载(请参见可重载的运算符)。op-type 和 op-type2 中至少有一个必须是封闭类型(即运算符所属的类型,或理解为自定义的类型)。例如,这将防止重定义整数加法运算符。
后两种形式声明了转换运算符。conv-type-in 和 conv-type-out 中正好有一个必须是封闭类型(即,转换运算符只能从它的封闭类型转换为其他某个类型,或从其他某个类型转换为它的封闭类型)。
运算符只能采用值参数,不能采用 ref 或 out 参数。
C# 要求成对重载比较运算符。如果重载了==,则也必须重载!=,否则产生编译错误。同时,比较运算符必须返回bool类型的值,这是与其他算术运算符的根本区别。
C# 不允许重载=运算符,但如果重载例如+运算符,编译器会自动使用+运算符的重载来执行+=运算符的操作。
运算符重载的其实就是函数重载。首先通过指定的运算表达式调用对应的运算符函数,然后再将运算对象转化为运算符函数的实参,接着根据实参的类型来确定需要调用的函数的重载,这个过程是由编译器完成。
任何运算符声明的前面都可以有一个可选的属性(C# 编程指南)列表。
可重载和不可重载运算符
下表描述了 C# 中运算符重载的能力:
运算符 | 描述 |
---|---|
+, -, !, ~, ++, -- | 这些一元运算符只有一个操作数,且可以被重载。 |
+, -, *, /, % | 这些二元运算符带有两个操作数,且可以被重载。 |
==, !=, <, >, <=, >= | 这些比较运算符可以被重载。 |
&&, || | 这些条件逻辑运算符不能被直接重载。 |
+=, -=, *=, /=, %= | 这些赋值运算符不能被重载。 |
=, ., ?:, ->, new, is, sizeof, typeof | 这些运算符不能被重载。 |
实例
public static void run() { User ua = new User(); ua.setFans(114514); ua.setFollows(1919810); Console.WriteLine($"Ua differ : {ua.getDiffer()}"); User ub = new User(); ub.setFans(42); ub.setFollows(618); Console.WriteLine($"Ub differ : {ub.getDiffer()}"); User uc = ua + ub; Console.WriteLine($"Uc differ : {uc.getDiffer()}"); Console.WriteLine($"Ua-Ub differ : {(ua- ub).getDiffer()}"); Console.WriteLine($"Ua+Ub differ : {(ua+ ub).getDiffer()}"); Console.WriteLine($"Ua*Ub differ : {(ua * ub).getDiffer()}"); Console.WriteLine($"Ua/Ub differ : {(ua / ub).getDiffer()}"); Console.WriteLine($"Ua>Ub : {(ua > ub)}"); Console.WriteLine($"Ua<Ub : {(ua < ub)}"); Console.WriteLine($"Ua<=Ub : {(ua <= ub)}"); Console.WriteLine($"Ua>=Ub : {(ua >= ub)}"); Console.WriteLine($"Ua!=Ub : {(ua != ub)}"); Console.WriteLine($"Ua==Ub : {(ua == ub)}"); } class User { private int fans; private int follows; public void setFans(int fan) { fans = fan; } public void setFollows(int follw) { follows = follw; } public int getDiffer() { return (fans+follows)-Math.Max(fans, follows); } //重载运算符 public static User operator+ (User ua,User ub) { User uc = new User(); uc.fans = ua.fans + ub.fans; uc.follows = ua.follows + ub.follows; return uc; } public static User operator /(User ua, User ub) { User uc = new User(); uc.fans = ua.fans / ub.fans; uc.follows = ua.follows / ub.follows; return uc; } public static User operator *(User ua, User ub) { User uc = new User(); uc.fans = ua.fans * ub.fans; uc.follows = ua.follows * ub.follows; return uc; } public static User operator -(User ua, User ub) { User uc = new User(); uc.fans = ua.fans - ub.fans; uc.follows = ua.follows - ub.follows; return uc; } public static bool operator <(User ua, User ub) { return (ua.fans + ua.follows < ub.fans + ub.follows); } public static bool operator >(User ua, User ub) { return (ua.fans + ua.follows > ub.fans + ub.follows); } public static bool operator <=(User ua, User ub) { return (ua.fans+ua.follows <= ub.fans+ub.follows) ; } public static bool operator >=(User ua, User ub) { return (ua.fans + ua.follows >= ub.fans + ub.follows) ; } public static bool operator!=(User ua, User ub) { return (ua.fans != ub.fans) | (ua.follows != ub.follows);; } public static bool operator==(User ua, User ub) { return (ua.fans==ub.fans)&&(ua.follows==ub.follows); } }
Ua differ : 114514 Ub differ : 42 Uc differ : 114556 Ua-Ub differ : 114472 Ua+Ub differ : 114556 Ua*Ub differ : 4809588 Ua/Ub differ : 2726 Ua>Ub : True Ua<Ub : False Ua<=Ub : False Ua>=Ub : True Ua!=Ub : True Ua==Ub : False