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; } publicvoid 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