← 筆記

C#筆記 – 操作符方法

操作符****重載
  • CLR對操作符的含義一無所知,但規定了語言如何公開操作符重載的方法
    • 需要是public static的

    • 需要包含operator關鍵字以及對應的操作符符號

    • 比如 + 操作符重載

      •   public sealed class Complex
          {
              public static Complex operator+(Complex c1, Complex c2) 
              {
                  return null;
              }
          }
      •   .method public hidebysig specialname static 
                  class CLR_Ch8.Complex  op_Addition(class CLR_Ch8.Complex c1,
                                                     class CLR_Ch8.Complex c2) cil managed
          {
            // 程式碼大小       7 (0x7)
            .maxstack  1
            .locals init (class CLR_Ch8.Complex V_0)
            IL_0000:  nop
            IL_0001:  ldnull
            IL_0002:  stloc.0
            IL_0003:  br.s       IL_0005
            IL_0005:  ldloc.0
            IL_0006:  ret
          } // end of method Complex::op_Addition
      • 編譯器為名為op_Addition的方法生成元數據方法定義項,並設置了specialname標志

      • C#編譯器在看到 + 操作符後,會檢查是否有一個操作數的類型定義了名為 op_Addition的specialname方法

        • 如果方法存在,且參數兼容於操作數的類型,就生成調用該方法的代碼
    • C#一元操作符及相容CLS方法名

      • C#操作符特殊方法名相容於CLS的方法名
        +op_UnaryPlusPlus
        -op_UnaryNegationNegate
        !op_LogicalNotNot
        ~op_OnesComplementOnesComplement
        ++op_IncrementIncrement
        op_DecrementDecrement
        (無)op_TrueIsTrue{ get; }
        (無)op_FalseIsFalse{ get; }
    • C#二元操作符及相容CLS方法名

      • C#操作符特殊方法名相容於CLS的方法名
        +op_AdditionAdd
        -op_SubtractionSubtract
        *op_MultiplyMultiply
        /op_DivisionDivide
        %op_ModulusMod
        &op_BitwiseAndBitwiseAnd
        |op_BitwiseOrBitwiseOr
        ^op_ExclusiveOrXor
        <<op_LeftShiftLeftShift
        >>op_RightShiftRightShift
        ==op_EqualityEquals
        !=op_InequalityEquals
        <op_LessThanCompare
        >op_GreaterThanCompare
        <=op_LessThanOrEqualCompare
        >=op_GreaterThanOrEqualCompare
轉換操作符
  • 如果源對象和目標都是編譯器識別的基元類型,編譯器自己就知道如何生成轉換對象所需的代碼
  • 如果源對象或目標不是編譯器識別的基元類型,編譯器會生成代碼,要求CLR執行轉換(強制轉型)
    • CLR會檢查源對象類型和目標類型是不是相同
  • 但是如果要把一個類型轉換成完全不同的類型,就需要定義相關的轉換方法
    • 這個類型要有一些成員:

      • 接收一個參數的公共構造器,讓參數類型隱式轉換自己
      • 無參的公共實例方法,把自己顯式轉換成其他類型
      • 具體的轉換操作符重載方法
        • 必須是public static
        • 參數類型和返回類型二者必有其一與定義轉換方法的類型相同
        • 隱式轉換方法:public static implict operator 目標類型(源類型)
          • 只有在轉換不損失精度的情況下可以定義
        • 顯式轉換方法:public static explict operator 目標類型(源類型)
          • 如果轉換會損失精度,需要定義顯式轉換
    • C#

      •   public sealed class Rational
          {
              public Rational(int num) { }
              public Rational(float num) { }
          
              public int ToInt() { return default; }
              public float ToFloat() { return default; }
          
          
              //int/float 隱式轉型至 Rational
              public static implicit operator Rational(int num)
              {
                  return new Rational(num);
              }
              public static implicit operator Rational(float num)
              {
                  return new Rational(num);
              }
          
              //Rational 顯式轉型 int/float
              public static explicit operator int(Rational r)
              {
                  return r.ToInt();
              }
              public static explicit operator float(Rational r)
              {
                  return r.ToFloat();
              }
          }
    • metadata

  • C#編譯器檢測到代碼的轉型後,會生成IL來調用定義好的轉換操作符方法
    • 如果代碼正使用某類型對象,但實際期望是另一個類型,編譯器會查找能執行這種轉換的隱式轉換操作符方法,並在IL中生成調用代碼
    • 如果編譯器看到代碼存在顯式轉換,就會查找能行這種轉換的「隱式/顯式」轉換操作符方法,如果找到一個,就生成IL調用
  • 使用C#的as 或 is操作符時,永遠不會調用這些定義的轉換方法

參考書目

  • 《CLR via C#》(第4版) Jeffrey Richter