zoukankan      html  css  js  c++  java
  • 深入解析事件

    1 事件的由来

      在介绍事件之前大家可以先看看下面的例子, PriceManager 负责对商品价格进行处理,当委托对象 GetPriceHandler 的返回值大于100元,按8.8折计算,低于100元按原价计算。

     1     public delegate double PriceHandler();
     2 
     3     public class PriceManager
     4     {
     5         public PriceHandler GetPriceHandler;
     6 
     7         //委托处理,当价格高于100元按8.8折计算,其他按原价计算
     8         public double GetPrice()
     9         {
    10             if (GetPriceHandler.GetInvocationList().Count() > 0)
    11             {
    12                 if (GetPriceHandler() > 100)
    13                     return GetPriceHandler()*0.88;
    14                 else
    15                     return GetPriceHandler();
    16             }
    17             return -1;
    18         }
    19     }
    20 
    21     class Program
    22     {
    23         static void Main(string[] args)
    24         {
    25             PriceManager priceManager = new PriceManager();
    26             
    27             //调用priceManager的GetPrice方法获取价格
    28             //直接调用委托的Invoke获取价格,两者进行比较
    29             priceManager.GetPriceHandler = new PriceHandler(ComputerPrice);
    30             Console.WriteLine(string.Format("GetPrice
      Computer's price is {0}!",
    31                 priceManager.GetPrice()));
    32             Console.WriteLine(string.Format("Invoke
      Computer's price is {0}!",
    33                 priceManager.GetPriceHandler.Invoke()));
    34             
    35             Console.WriteLine();
    36             
    37             priceManager.GetPriceHandler = new PriceHandler(BookPrice);
    38             Console.WriteLine(string.Format("GetPrice
      Book's price is {0}!",
    39                 priceManager.GetPrice()));
    40             Console.WriteLine(string.Format("Invoke
      Book's price is {0}!" ,
    41                 priceManager.GetPriceHandler.Invoke()));
    42             
    43             Console.ReadKey();
    44         }
    45         //书本价格为98元
    46         public static double BookPrice()
    47         {
    48             return 98.0;
    49         }
    50         //计算机价格为8800元
    51         public static double ComputerPrice()
    52         {
    53             return 8800.0;
    54         }
    55     }

    运行结果

      观察运行的结果,如果把委托对象 GetPriceHandler 设置为 public ,外界可以直接调用 GetPriceHandler.Invoke 获取运行结果而移除了 GetPrice 方法的处理,这正是开发人员最不想看到的。
      为了保证系统的封装性,开发往往需要把委托对象 GetPriceHandler 设置为 private, 再分别加入 AddHandler,RemoveHandler 方法对 GetPriceHandler 委托对象进行封装。

     1     public delegate double PriceHandler();
     2 
     3     public class PriceManager
     4     {
     5         private PriceHandler GetPriceHandler;
     6 
     7         //委托处理,当价格高于100元按8.8折计算,其他按原价计算
     8         public double GetPrice()
     9         {
    10             if (GetPriceHandler!=null)
    11             {
    12                 if (GetPriceHandler() > 100)
    13                     return GetPriceHandler()*0.88;
    14                 else
    15                     return GetPriceHandler();
    16             }
    17             return -1;
    18         }
    19 
    20         public void AddHandler(PriceHandler handler)
    21         {
    22             GetPriceHandler += handler;
    23         }
    24 
    25         public void RemoveHandler(PriceHandler handler)
    26         {
    27             GetPriceHandler -= handler;
    28         }
    29     }
    30     ................
    31     ................

      为了保存封装性,很多操作都需要加入AddHandler、RemoveHandler 这些相似的方法代码,这未免令人感到厌烦。
      为了进一步简化操作,事件这个概念应运而生。
     

    2 事件的定义

      事件(event)可被视作为一种特别的委托,它为委托对象隐式地建立起add_XXX、remove_XXX 两个方法,用作注册与注销事件的处理方法。而且事件对应的变量成员将会被视为 private 变量,外界无法超越事件所在对象直接访问它们,这使事件具备良好的封装性,而且免除了add_XXX、remove_XXX等繁琐的代码。

    1     public class EventTest
    2     {
    3         public delegate void MyDelegate();
    4         public event MyDelegate MyEvent;
    5     }

      观察事件的编译过程可知,在编译的时候,系统为 MyEvent 事件自动建立add_MyEvent、remove_MyEvent 方法。

     

    3 事件的使用方式

      事件能通过+=和-=两个方式注册或者注销对其处理的方法,使用+=与-=操作符的时候,系统会自动调用对应的 add_XXX、remove_XXX 进行处理。
      值得留意,在PersonManager类的Execute方法中,如果 MyEvent 绑定的处理方法不为空,即可使用MyEvent(string)引发事件。但如果在外界的 main 方法中直接使用 personManager.MyEvent (string) 来引发事件,系统将引发错误报告。这正是因为事件具备了良好的封装性,使外界不能超越事件所在的对象访问其变量成员。

    注意在事件所处的对象之外,事件只能出现在+=,-=的左方。

    此时,开发人员无须手动添加 add_XXX、remove_XXX 的方法,就可实现与4.1例子中的相同功能,实现了良好的封装。

     1     public delegate void MyDelegate(string name);
     2 
     3     public class PersonManager
     4     {
     5         public event MyDelegate MyEvent;
     6 
     7         //执行事件
     8         public void Execute(string name)
     9         {
    10             if (MyEvent != null)
    11                 MyEvent(name);
    12         }
    13     }
    14 
    15     class Program
    16     {
    17         static void Main(string[] args)
    18         {
    19             PersonManager personManager = new PersonManager();
    20             //绑定事件处理方法
    21             personManager.MyEvent += new MyDelegate(GetName);
    22             personManager.Execute("Leslie");
    23             Console.ReadKey();
    24         }
    25 
    26         public static void GetName(string name)
    27         {
    28             Console.WriteLine("My name is " + name);
    29         }
    30     }

     

    4 事件处理方法的绑定

      在绑定事件处理方法的时候,事件出现在+=、-= 操作符的左边,对应的委托对象出现在+=、-= 操作符的右边。对应以上例子,事件提供了更简单的绑定方式,只需要在+=、-= 操作符的右方写上方法名称,系统就能自动辩认。

     1     public delegate void MyDelegate(string name);
     2 
     3     public class PersonManager
     4     {
     5         public event MyDelegate MyEvent;
     6         .........
     7     }
     8 
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             PersonManager personManager = new PersonManager();
    14             //绑定事件处理方法
    15             personManager.MyEvent += GetName;
    16             .............
    17         }
    18 
    19         public static void GetName(string name)
    20         {.........}
    21    }

    如果觉得编写 GetName 方法过于麻烦,你还可以使用匿名方法绑定事件的处理。

     1     public delegate void MyDelegate(string name);
     2 
     3     public class PersonManager
     4     {
     5         public event MyDelegate MyEvent;
     6 
     7         //执行事件
     8         public void Execute(string name)
     9         {
    10             if (MyEvent != null)
    11                 MyEvent(name);
    12         }
    13 
    14         static void Main(string[] args)
    15         {
    16             PersonManager personManager = new PersonManager();
    17             //使用匿名方法绑定事件的处理
    18             personManager.MyEvent += delegate(string name){
    19                 Console.WriteLine("My name is "+name);
    20             };
    21             personManager.Execute("Leslie");
    22             Console.ReadKey();
    23         }
    24     }

    来源:http://www.cnblogs.com/zhangyanhai/archive/2013/10/09/3359240.html
  • 相关阅读:
    Redis 错误摘记篇
    搭建备份到业务迁移---mysql
    业务迁移---web
    业务迁移---redis
    redis 编译安装错误问题
    location 匹配规则 (NGINX)
    nginx虚拟目录实现两个后台使用
    零基础学python-19.10 生成器是单迭代器
    零基础学python-19.9 生成器函数与生成器表达式
    零基础学python-19.8 生成器表达式:当迭代器遇上列表解析
  • 原文地址:https://www.cnblogs.com/xuekai-to-sharp/p/3368462.html
Copyright © 2011-2022 走看看