日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#构造函数、操作符重载以及自定义类型转换

發布時間:2023/12/9 C# 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#构造函数、操作符重载以及自定义类型转换 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

構造器


  構造器(構造函數)是將類型的實例初始化的特殊方法。構造器可分為實例構造器類型構造器,本節將詳細介紹有關內容。

實例構造器

  顧名思義,實例構造器的作用就是對類型的實例進行初始化。如果類沒有顯示定義任何構造器,C#編譯器會定義一個默認的無參構造器。相反,如果類中已經顯示地定義了一個構造器,那么就不會再生成默認構造器了。定義實例構造器的語法這里就不再多做闡述了(該懂得要懂呀),下面通過一個簡單的示例講述實例構造器的執行原理。

public class Rapper {private string name;private int age;private bool real = true;public Rapper(string name,int age){this.name = name;this.age = age;} }

通過上述代碼,我們創建了一個Rapper類,并定義了一個實例構造器,下面通過ildasm.exe工具查看構造器方法(.ctor)的IL代碼。

.method public hidebysig specialname rtspecialname instance void .ctor(string name,int32 age) cil managed {// Code size 30 (0x1e).maxstack 8IL_0000: ldarg.0IL_0001: ldc.i4.1IL_0002: stfld bool ConsoleApplication5.Rapper::realIL_0007: ldarg.0IL_0008: call instance void [mscorlib]System.Object::.ctor()IL_000d: nopIL_000e: nopIL_000f: ldarg.0IL_0010: ldarg.1IL_0011: stfld string ConsoleApplication5.Rapper::nameIL_0016: ldarg.0IL_0017: ldarg.2IL_0018: stfld int32 ConsoleApplication5.Rapper::ageIL_001d: ret } // end of method Rapper::.ctor

執行步驟:

  • Rapper的構造器把值true存儲到字段real
  • 調用Object類的構造器
  • 加載第一個參數存儲到字段name
  • 加載第二個參數存儲到字段age
  • 雖然我們在聲明real字段時直接賦值為true,但是在編譯時,編譯器會將這種語法轉換成構造器方法中的代碼來進行初始化。

    我們知道,一個類型可以定義多個構造器,每個構造器須有不同簽名,將Rapper類稍加修改.

    public class Rapper {private string name;private int age;private bool real = true;private bool diss = true;private bool forgetWords = true;public Rapper(string name, int age){this.name = name;this.age = age;}public Rapper(string name){this.name = name;} }

    通過ildasm.exe工具查看兩段構造器的IL代碼,會發現在每個方法開始的位置都包含用于初始化real,diss,forgetWords的代碼

    為了減少生成的代碼,可以利用this關鍵字顯式調用另外一個構造器

    public class Rapper {private string name;private int age;private bool real = true;private bool diss = true;private bool forgetWords = true;public Rapper(string name, int age) : this(name){this.age = age;}public Rapper(string name){this.name = name;} }

    到目前為止,我們討論的都是引用類型的實例構造器,下面,再來看看值類型的實例構造器。這里只用一句話來概括:值類型不允許包含顯式的無參數構造器,如果為值類型定義構造器,必須顯示調用才會執行

    類型構造器

      類型構造器也稱靜態構造函數,類型構造器的作用是設置類型的初始狀態。類型默認沒有定義類型構造器。如果定義,只能定義一個。類型構造器沒有參數。

    類型構造器的特點:

  • 定義類型構造器類似于實例構造器,區別在于必須標記為static
  • 類型構造器總是私有的,靜態構造器不允許出現訪問修飾符
  • 類型構造器的執行原理:

  • JIT編譯在編譯一個方法時,會查看代碼中所有引用的類型
  • 判斷類型是否定義了類型構造器
  • 針對當前的AppDomain,檢查是否已經調用了該類型構造器
  • 如果沒有,JIT編譯器會在生成的native代碼中添加對類型構造器的調用
  • 類型構造器中的代碼只能訪問靜態字段,與實例構造器相同,在類中聲明靜態字段并直接賦值時,編譯器會自動生成一個類型構造器,并在類型構造器中初始化該值。為上面的Rapper類添加靜態字段hobby

    private static string hobby = "rap";

    查看類型構造器方法(.cctor)的IL代碼。

    .method private hidebysig specialname rtspecialname static void .cctor() cil managed {// Code size 11 (0xb).maxstack 8IL_0000: ldstr "rap"IL_0005: stsfld string ConsoleApplication5.Rapper::hobbyIL_000a: ret } // end of method Rapper::.cctor


    操作符重載方法


      有的語言允許類型定義操作符來操作類型的實例。CLR對操作符一無所知,是編程語言定義了每個操作符的含義,以及調用這些操作符時生成的代碼。向Rapper類添加如下代碼:

    public static string operator +(Rapper rapperA, Rapper rapperB){if (rapperA.name == "PGOne" || rapperB.name == "PGOne"){return "diss";}return "peace";}

    注意:

  • CLR規范要求操作符重載方法必須是public和static方法
  • 使用operator關鍵字告訴編譯器,這是一個自定義操作符重載方法
  • 修改Main方法,聲明兩個Rapper對象,并輸出rapperA + rapperB的返回值。

    class Program {static void Main(string[] args){Rapper rapperA = new Rapper("PGOne");Rapper rapperB = new Rapper("GAI");Console.WriteLine(rapperA + rapperB); //dissConsole.ReadLine();} }

    下面,使用ILDasm.exe工具查看編譯器生成的IL代碼。

    .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 43 (0x2b) .maxstack 2 .locals init ([0] class ConsoleApplication5.Rapper rapperA,[1] class ConsoleApplication5.Rapper rapperB) IL_0000: nop IL_0001: ldstr "PGOne" IL_0006: newobj instance void ConsoleApplication5.Rapper::.ctor(string) IL_000b: stloc.0 IL_000c: ldstr "GAI" IL_0011: newobj instance void ConsoleApplication5.Rapper::.ctor(string) IL_0016: stloc.1 IL_0017: ldloc.0 IL_0018: ldloc.1 IL_0019: call string ConsoleApplication5.Rapper::op_Addition(class ConsoleApplication5.Rapper,class ConsoleApplication5.Rapper) IL_001e: call void [mscorlib]System.Console::WriteLine(string) IL_0023: nop IL_0024: call string [mscorlib]System.Console::ReadLine() IL_0029: pop IL_002a: ret } // end of method Program::Main

    通過IL_0019一行,我們可以看到代碼中出現+操作符時,實際調用的是op_Addition方法,再查看op_Addition方法的IL代碼。

    .method public hidebysig specialname static string op_Addition(class ConsoleApplication5.Rapper rapperA,class ConsoleApplication5.Rapper rapperB) cil managed { // Code size 61 (0x3d) .maxstack 2 .locals init ([0] bool V_0,[1] string V_1) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldfld string ConsoleApplication5.Rapper::name IL_0007: ldstr "PGOne" IL_000c: call bool [mscorlib]System.String::op_Equality(string,string) IL_0011: brtrue.s IL_0025 IL_0013: ldarg.1 IL_0014: ldfld string ConsoleApplication5.Rapper::name IL_0019: ldstr "PGOne" IL_001e: call bool [mscorlib]System.String::op_Equality(string,string) IL_0023: br.s IL_0026 IL_0025: ldc.i4.1 IL_0026: stloc.0 IL_0027: ldloc.0 IL_0028: brfalse.s IL_0033 IL_002a: nop IL_002b: ldstr "diss" IL_0030: stloc.1 IL_0031: br.s IL_003b IL_0033: ldstr "peace" IL_0038: stloc.1 IL_0039: br.s IL_003b IL_003b: ldloc.1 IL_003c: ret } // end of method Rapper::op_Addition

    執行步驟:

  • 編譯器為op_Addition方法生成元數據方法定義項,并在定義項中設置了specialname標志,表明這是一個特殊方法。
  • 編譯器發現代碼中出現+操作符時,會檢查是否有一個操作數的類型定義了名為op_Addition的specialname方法,而且該方法的參數兼容于操作數的類型。
  • 如果存在這樣的方法,就生成調用它的代碼。

  • 轉換操作符方法


      有時需要將對象從一種類型轉換為另外一種全然不同的其他類型,此時便可以通過轉換操作符實現自定義類型轉換。同樣的,CLR規范要求轉換操作符重載方法必須是public和static的,并且要求參數類型和返回類型二者必有其一與定義轉換方法的類型相同

      在C#中使用implicitexplicit關鍵字定義隱式/顯示類型轉換。在Implicit或explicit關鍵字后,要指定operator關鍵字告訴編譯器該方法是一個轉換操作符。在operator之后,指定目標類型,而在參數部分指定源類型。
    依舊沿用上面的示例,為Rapper類添加Rap方法,并為其添加無參構造函數。

    public void Rap() {Console.WriteLine("Rap"); }public Rapper() {}

    新增Dancer類,添加Dance方法,使用implicit/explicit關鍵字定義隱式/顯示類型轉換。

    public class Dancer {public void Dance(){Console.WriteLine("Breaking");}public static implicit operator Rapper(Dancer dancer){return new Rapper();}public static explicit operator Dancer(Rapper rapper){return new Dancer();} }

    修改Main方法:

    class Program {static void Main(string[] args){Rapper rapperA = new Rapper();Dancer dancerA = (Dancer)rapperA;dancerA.Dance(); //BreakingDancer dancerB = new Dancer();Rapper rapperB = dancerB;rapperB.Rap(); //RapConsole.ReadLine();} }

    最后,查看編譯器生成的IL代碼可以發現,將對象從一種類型轉換為另一種類型的方法總是叫做op_Implicitop_Explicit

    .method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 48 (0x30) .maxstack 1 .locals init ([0] class ConsoleApplication5.Rapper rapperA,[1] class ConsoleApplication5.Dancer dancerA,[2] class ConsoleApplication5.Dancer dancerB,[3] class ConsoleApplication5.Rapper rapperB) IL_0000: nop IL_0001: newobj instance void ConsoleApplication5.Rapper::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: call class ConsoleApplication5.Dancer ConsoleApplication5.Dancer::op_Explicit(class ConsoleApplication5.Rapper) IL_000d: stloc.1 IL_000e: ldloc.1 IL_000f: callvirt instance void ConsoleApplication5.Dancer::Dance() IL_0014: nop IL_0015: newobj instance void ConsoleApplication5.Dancer::.ctor() IL_001a: stloc.2 IL_001b: ldloc.2 IL_001c: call class ConsoleApplication5.Rapper ConsoleApplication5.Dancer::op_Implicit(class ConsoleApplication5.Dancer) IL_0021: stloc.3 IL_0022: ldloc.3 IL_0023: callvirt instance void ConsoleApplication5.Rapper::Rap() IL_0028: nop IL_0029: call string [mscorlib]System.Console::ReadLine() IL_002e: pop IL_002f: ret } // end of method Program::Main


    擴展方法


      擴展方法已經在《從LINQ開始之LINQ to Objects(下)》一文中進行了詳細介紹,本篇就不再重復了。

    轉載于:https://www.cnblogs.com/Answer-Geng/p/7481294.html

    總結

    以上是生活随笔為你收集整理的C#构造函数、操作符重载以及自定义类型转换的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。