• c#中的事件


    之前的博客讲到委托,委托本质上是将方法作为方法的参数传给方法。实际开发中,实现某个功能的的代码通常会封装成一个类,本例中字符串处理封装成MyStringProc类,
    代码如下:
     1 namespace DelegateTest
     2 {
     3     public delegate string MyStringProcDelegate(string str);
     4     class MyStringProc
     5     {
     6         public string ProcString(string str,MyStringProcDelegate strProcDelegate)
     7         {
     8             return strProcDelegate(str);
     9         }
    10     }
    11 }
    View Code

    在调用的时候实例化这个类,再调用对应的方法。如下:

     1 namespace DelegateTest
     2 {
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             MyStringProc msp = new MyStringProc();
     8             string str1=msp.ProcString("I am good.", StringToLower);
     9             string str2 = msp.ProcString("I am good too", StringToUpper);
    10             Console.WriteLine("{0},{1}",str1,str2);
    11             Console.ReadKey();
    12         }
    13         static string StringToLower(string str)
    14         {
    15             return str.ToLower();
    16         }
    17         static string StringToUpper(string str)
    18         {
    19             return str.ToUpper();
    20         }
    21     }
    22 }
    View Code
    输出如下:
     
    现在如果要实现某个功能,这个功能包含多种类型但操作参数都相同,只是内部逻辑不同,而且要依次调用其中几个,这时我们可以只定义一个委托变量,将这些操作的方法依次绑定到这个委托变量即可。
    下面是处理一个字符串:字符串前后加'[]',前后后加'{}',代码如下:
     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             MyStringProc msp = new MyStringProc();
     6             MyStringProcDelegate strProcDelegate;
     7             strProcDelegate = StringProc1;
     8             strProcDelegate += StringProc2;
     9             msp.ProcString("I am a good boy",strProcDelegate);
    10             Console.ReadKey();
    11         }
    12 
    13         static string StringProc1(string str)
    14         {
    15             str= "["+str+"]";
    16             Console.WriteLine(str);
    17             return str;
    18         }
    19         static string StringProc2(string str)
    20         {
    21             str= "{" + str + "}";
    22             Console.WriteLine(str);
    23             return str;
    24         }
    25     }
    View Code

    输出如下:

    以上并没有达到完全封装,本例用到的MyStringProcDelegate类型的委托变量是可以封装在MyStringProc类中,客户端直接调用该类的方法即可,无需再声明委托变量。如下:

     1 public delegate string MyStringProcDelegate(string str);
     2     class MyStringProc
     3     {
     4         public MyStringProcDelegate strProcDelegate;
     5         public string ProcString(string str)
     6         {
     7             if (strProcDelegate!=null)
     8                 str=strProcDelegate(str);
     9             return str;
    10         }
    11     }
    View Code

    调用代码如下:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             MyStringProc msp = new MyStringProc();
     6             msp.strProcDelegate = StringProc1;
     7             msp.strProcDelegate += StringProc2;
     8             msp.ProcString("I am a good boy");
     9             Console.ReadKey();
    10         }
    11         static string StringProc1(string str)
    12         {
    13             str= "["+str+"]";
    14             Console.WriteLine(str);
    15             return str;
    16         }
    17         static string StringProc2(string str)
    18         {
    19             str= "{" + str + "}";
    20             Console.WriteLine(str);
    21             return str;
    22         }
    23     }
    View Code

    输出如下:

     
    事件
    上面的改进无需再客户端声明委托变量,直接调用功能类的方法即可,但是委托变量声明成了public类型,意思就是说客户端可以随意操作该委托变量,破环了面向对象中的封装性。
    假如我们将委托变量进行封装,类似于对字段的封装成属性,在c#中event就是对委托类型变量的一种封装,加上event关键字实际上是将普通的委托封装成具有Add和Remove方法
    的一种特殊的委托,后面我用reflector反编译工具查看。
     
    代码修改如下:
     1 public delegate string MyStringProcDelegate(string str);
     2     class MyStringProc
     3     {
     4         public event MyStringProcDelegate strProcDelegate;
     5         public string ProcString(string str)
     6         {
     7             if (strProcDelegate != null)
     8                 str = strProcDelegate(str);
     9             return str;
    10         }
    11     }
    View Code

    调用方法如下:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             MyStringProc msp = new MyStringProc();
     6             msp.strProcDelegate += StringProc1;
     7             msp.strProcDelegate += StringProc2;
     8             msp.ProcString("I am a good boy");
     9             Console.ReadKey();
    10         }
    11         static string StringProc1(string str)
    12         {
    13             str= "["+str+"]";
    14             Console.WriteLine(str);
    15             return str;
    16         }
    17         static string StringProc2(string str)
    18         {
    19             str= "{" + str + "}";
    20             Console.WriteLine(str);
    21             return str;
    22         }
    23     }
    View Code

    输出如下:

    这样做的好处是,限定了委托的使用,可防止已注册该事件的方法被非法调用。注:事件只能用+=或-=。
    下面是对定义的strProcDelegate 变量反编译结果,从中可看出我们在类中定义的该委托变量最终会编译成add、remove两个方法,add为对委托注册方法,remove为对委托取消注册方法。
     
    而且虽然strProcDelegate 变量声明称public,但最终会编译成private,如下:
     
    MyStringProcDelegate委托类型最终编译如下:
  • 相关阅读:
    今週のschedule
    软件架构师应该知道的97件事
    没办法的复习
    优秀程序员的45个习惯
    程序员如何追女孩
    那些相见恨晚的 JavaScript 技巧
    CodeSmith开发系列资料总结
    HR的至高机密:20个公司绝对不会告诉你的潜规则
    asp.net页面出错时的处理方法
    Asp.net 文件上传的 FileUpload FileName 和 FileUpload PostedFile.FileName的细节问题
  • 原文地址:https://www.cnblogs.com/kungge/p/4713627.html
Copyright © 2020-2023  润新知