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