程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 編寫高質量代碼改善C#程序的157個建議——建議39:了解委托的實質,

編寫高質量代碼改善C#程序的157個建議——建議39:了解委托的實質,

編輯:C#入門知識

編寫高質量代碼改善C#程序的157個建議——建議39:了解委托的實質,


建議39:了解委托的實質

理解C#中的委托需要把握兩個要點:

1)委托是方法指針。

2)委托是一個類,當對其進行實例化的時候,要將引用方法作為它的構造方法的參數。

設想這樣一個場景:在點對點文件傳輸過程當中,我們要設計一個文件傳輸類,該傳輸類起碼要滿足下面幾項功能:

  • 傳輸問題件;
  • 按照百分制通知傳輸進度;
  • 傳輸類能夠同時被控制台程序和WinForm應用程序使用。

由於要讓通知本身能夠被控制台程序和WinFrom應用程序使用,因此設計這個文件傳輸類在進行進度通知時,就不能顯示調用:

Console.WriteLine("當前進度:"+fileProgress);

或者

this.progressText.Text = "當前進度:" + fileProgress;

理想情況下是,在需要通知的地方,全部將其置換成一個方法的指針,由調用者來決定該方法完成什麼功能。這個方法指針在C#中就是委托。可以像下面那樣聲明委托:

public delegate void FileUploadedHandler(int progress);

這個文件傳輸類可以寫成這樣:

    class FileUploader
    {
        public delegate void FileUploadedHandler(int progress);
        public FileUploadedHandler FileUploaded;
        
        public void Upload()
        {
            int fileProgress = 100;
            while (fileProgress > 0)
            {
                //傳輸代碼,省略
                fileProgress--;
                if (FileUploaded != null)
                {
                    FileUploaded(fileProgress);
                }
            }
        }
    }

調用者在調用這個文件傳輸類的時候,應該同時為FileUploaded賦值,賦值過程中也就是將自身所具有的和委托聲明相同的聲明方法賦值給FileUploaded。這樣,類型FileUploader在執行到下面的代碼時,就是執行調用者自身的方法

 FileUploaded(fileProgress);

理解了“委托是方法指針”這一點後,在了理解“委托是一個類”。

查看下面這句話:

public delegate void FileUploadedHandler(int progress);

它的IL代碼為:

.class auto ansi sealed nested public FileUploadedHandler
    extends [mscorlib]System.MulticastDelegate
{
    .method public hidebysig specialname rtspecialname instance void .ctor(object 'object', native int 'method') runtime managed
    {
    }

    .method public hidebysig newslot virtual instance class [mscorlib]System.IAsyncResult BeginInvoke(int32 progress, class [mscorlib]System.AsyncCallback callback, object 'object') runtime managed
    {
    }

    .method public hidebysig newslot virtual instance void EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
    {
    }

    .method public hidebysig newslot virtual instance void Invoke(int32 progress) runtime managed
    {
    }

}

調用委托方法:

FileUploaded(fileProgress);

其實是調用:

FileUploaded.Invok(fileProgress);

可以查看Upload方法的IL代碼:

.method public hidebysig instance void Upload() cil managed
{
    .maxstack 2
    .locals init (
        [0] int32 fileProgress,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.s 100
    L_0003: stloc.0 
    L_0004: br.s L_0028
    L_0006: nop 
    L_0007: ldloc.0 
    L_0008: ldc.i4.1 
    L_0009: sub 
    L_000a: stloc.0 
    L_000b: ldarg.0 
    L_000c: ldfld class MyTest.FileUploader/FileUploadedHandler MyTest.FileUploader::FileUploaded
    L_0011: ldnull 
    L_0012: ceq 
    L_0014: stloc.1 
    L_0015: ldloc.1 
    L_0016: brtrue.s L_0027
    L_0018: nop 
    L_0019: ldarg.0 
    L_001a: ldfld class MyTest.FileUploader/FileUploadedHandler MyTest.FileUploader::FileUploaded
    L_001f: ldloc.0 
    L_0020: callvirt instance void MyTest.FileUploader/FileUploadedHandler::Invoke(int32)
    L_0025: nop 
    L_0026: nop 
    L_0027: nop 
    L_0028: ldloc.0 
    L_0029: ldc.i4.0 
    L_002a: cgt 
    L_002c: stloc.1 
    L_002d: ldloc.1 
    L_002e: brtrue.s L_0006
    L_0030: ret 
}

可以看到L_0020處調用Invoke方法。

 

一句話:委托是一種數據類型,它用來傳遞方法。

 

轉自:《編寫高質量代碼改善C#程序的157個建議》陸敏技

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved