zoukankan      html  css  js  c++  java
  • 编写高质量代码改善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个建议》陆敏技

  • 相关阅读:
    时区 : America/Mexico_City 中文:美国中部时间(墨西哥城) 的夏令时
    Android中的常见时区
    嵌套滚动demo
    Android之获得内存剩余大小与总大小
    通过ip获取地理位置信息
    9.png(9位图)在android中作为background使用导致居中属性不起作用的解决方法
    Android ActivityManagerService 基本构架详解
    Eclipse 常用快捷键 (动画讲解)(转载)
    eclipse安装svn插件,在输入url后,一直卡在in progress界面不懂。
    android——背景颜色渐变(梯度变化)
  • 原文地址:https://www.cnblogs.com/jesselzj/p/4732926.html
Copyright © 2011-2022 走看看