跟小靜讀CLR via C#(08)-操作符
對於操作符,我們並不陌生,例如+,-,*,%等二元操作符,以及++,!等一元操作符。但是對於非基元類型,我們需要通過一些自訂方法才能使用這些操作符。今天主要和大家分享關於操作符重載和轉換操作符的知識。
一、操作符重載方法
CLR並不知道操作符,操作符重載對於它來說只是一些方法而已。但是CLR規定了語言應該如何公開操作符重載,每種程式設計語言自行決定是否支援操作符重載。
定義操作符重載方法注意兩點:
- CLR規範要求操作符重載方法必須是 public static 類型。
- C#要求操作符重載方法必須有一個參數的類型和當前定義這個方法的類型相同。否則會產生編譯錯誤
操作符重載執行個體
我們為非基元類型Complex重載操作符 “+”.
定義之後,可以使非基元類型Complex方便的進行+操作。
Sepecialname標記
ILDaxm.exe查看Complex類的中繼資料,發現產生了一個op_Addition項。如果重載其他動作符,也會自動產生相應的specialname標記。
在編譯過程中,當代碼中出現“+”操作符時,編譯器會自動檢查op_Addition的specialname標記,並且檢測參數類型相容性。
下面兩個表是C#允許重載的一元操作符和二元操作符。簡單瞭解一下就好,沒必要強記。
二、轉換操作符方法
當兩個非基元類型的執行個體需要相互轉換時,我們需要定義轉換操作符方法。轉換操作符是指將對象從一個類型轉換成另一個類型的方法。
兩大規定
- CLR要求轉換操作符重載方法必須是public static 方法。
- C#要求參數類型和傳回型別必須至少有一個與定義轉換方法的類型相同。
另外,為了完成轉換操作,我們應該在類型內定義兩類方法:
- 執行個體公用構造器。參數是源類型的執行個體
- 無參公用執行個體方法Toxxx。該方法將定義類型的執行個體轉換成xxx類型。
轉換操作符例子
為Rational(有理數)類型定義轉換操作符,方便與Int32類型執行個體進行相互轉換。
implicit和explicit
在這個例子中,我們定義了兩種轉換操作符方法:implicit關鍵字表示在原始碼中不需要進行顯式轉型;explicit關鍵字表示進行顯式轉型時才調用該方法。Operator關鍵字表明該方法是一個轉型操作符。
使用ILDasm.exe查看,
可以發現添加了兩個方法:op_Explicit和op_Implicit。只有當轉換後不丟失精度的前提下,才能進行隱式轉換;如果會發生精度丟失,則只能定義為顯式轉換。
定義完成之後我們就可以方便的進行轉型調用了。
static void Main(string[] args)
{
Rational r1 = 5; // 隱式轉換
Int32 x = (Int32)r1; // 顯示轉換
}
關於重載
在上面的例子中,實際上一個類型經常會和多個類型執行個體進行轉換操作,此時就需要再定義其他轉換操作符,例如public static explicit operator Single(Rational r),也就是進行方法重載。對於重載,我們並不陌生,特殊之處在於這兩個explicit重載方法僅僅通過傳回值類型不同來區分的。
CLR允許定義多個同名方法,只要每個方法的參數或者傳回值類型有所區別即可。但是在C#判斷方法的唯一性時,除了方法名稱外只考慮參數的區別,而忽略掉方法的傳回型別。所以,上面的兩個重載方法僅有傳回型別的差異實際上是C#放寬限制的特例。