如何理解.Net事件

发布时间:2021-10-29 17:36:24 作者:柒染
来源:亿速云 阅读:138

今天就跟大家聊聊有关如何理解.Net事件,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

.NET 事件

事件概述

在发生其他类或对象关注的事情时,类或对象可通过事件通知它们。发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。

事件的订阅和取消

如果您想编写引发事件时调用的自定义代码,则可以订阅由其他类发布的事件。例如,可以订阅某个按钮的“单击”事件,以使应用程序在用户单击该按钮时执行一些有用的操作。

publisher.RaiseCustomEvent += HandleCustomEvent; publisher.RaiseCustomEvent += new CustomEventHandler(HandleCustomEvent);
  1. publisher.RaiseCustomEvent += delegate(object o, CustomEventArgs e) 

  2.     string s = o.ToString() + " " + e.ToString(); 

  3.     Console.WriteLine(s); 

  4. };

要防止在引发事件时调用事件处理程序,您只需取消订阅该事件。要防止资源泄露,请在释放订户对象之前取消订阅事件,这一点很重要。在取消订阅事件之前,在发布对象中作为该事件的基础的多路广播委托会引用封装了订户的事件处理程序的委托。只要发布对象包含该引用,就不会对订户对象执行垃圾回收。

使用减法赋值运算符 (-=)  取消订阅事件。所有订户都取消订阅某事件后,发行者类中的事件实例会设置为 null。

publisher.RaiseCustomEvent -= HandleCustomEvent;

发布标准事件

下面的过程演示了如何将符合标准 .NET Framework 模式的事件添加到您自己的类和结构中。.NET Framework 类库中的所有事件均基于  EventHandler 委托,定义如下。

  1. public delegate void EventHandler(object sender, EventArgs e);

引发派生类中的基类事件

 以下简单示例演示了在基类中声明可从派生类引发的事件的标准方法。此模式广泛应用于 .NET Framework 基类库中的 Windows  窗体类。

在创建可用作其他类的基类的类时,必须考虑如下事实:事件是特殊类型的委托,只可以从声明它们的类中调用。派生类无法直接调用基类中声明的事件。尽管有时您可能希望某个事件只能通过基类引发,但在大多数情形下,您应该允许派生类调用基类事件。为此,您可以在包含该事件的基类中创建一个受保护的调用方法。通过调用或重写此调用方法,派生类便可以间接调用该事件。

namespace BaseClassEvents {     using System;     using System.Collections.Generic;     public class ShapeEventArgs : EventArgs     {         private double newArea;          public ShapeEventArgs(double d)         {             newArea = d;         }         public double NewArea         {             get { return newArea; }         }     }     public abstract class Shape     {         protected double area;          public double Area         {             get { return area; }             set { area = value; }         }         public event EventHandler<ShapeEventArgs> ShapeChanged;         public abstract void Draw();         protected virtual void OnShapeChanged(ShapeEventArgs e)         {             EventHandler<ShapeEventArgs> handler = ShapeChanged;             if (handler != null)             {                 handler(this, e);             }         }     }     public class Circle : Shape     {         private double radius;         public Circle(double d)         {             radius = d;             area = 3.14 * radius;         }         public void Update(double d)         {             radius = d;             area = 3.14 * radius;             OnShapeChanged(new ShapeEventArgs(area));         }         protected override void OnShapeChanged(ShapeEventArgs e)         {             base.OnShapeChanged(e);         }         public override void Draw()         {             Console.WriteLine("Drawing a circle");         }     }     public class Rectangle : Shape     {         private double length;         private double width;         public Rectangle(double length, double width)         {             this.length = length;             this.width = width;             area = length * width;         }         public void Update(double length, double width)         {             this.length = length;             this.width = width;             area = length * width;             OnShapeChanged(new ShapeEventArgs(area));         }         protected override void OnShapeChanged(ShapeEventArgs e)         {             base.OnShapeChanged(e);         }         public override void Draw()         {             Console.WriteLine("Drawing a rectangle");         }      }     public class ShapeContainer     {         List<Shape> _list;          public ShapeContainer()         {             _list = new List<Shape>();         }          public void AddShape(Shape s)         {             _list.Add(s);             s.ShapeChanged += HandleShapeChanged;         }         private void HandleShapeChanged(object sender, ShapeEventArgs e)         {             Shape s = (Shape)sender;             Console.WriteLine("Received event. Shape area is now {0}", e.NewArea);             s.Draw();         }     }     class Test     {          static void Main(string[] args)         {             Circle c1 = new Circle(54);             Rectangle r1 = new Rectangle(12, 9);             ShapeContainer sc = new ShapeContainer();             sc.AddShape(c1);             sc.AddShape(r1);             c1.Update(57);             r1.Update(7, 7);             Console.WriteLine();             Console.WriteLine("Press Enter to exit");             Console.ReadLine();         }     } }

实现接口事件

接口可声明事件。下面的示例演示如何在类中实现接口事件。接口事件的实现规则与任何接口方法或属性的实现规则基本相同。

     在类中声明事件,然后在适当的位置调用该事件。

  1. public interface IDrawingObject 

  2.     event EventHandler ShapeChanged; 

  3. public class MyEventArgs : EventArgs {&hellip;} 

  4. public class Shape : IDrawingObject 

  5.     event EventHandler ShapeChanged; 

  6.     void ChangeShape() 

  7.     { 

  8.         // Do something before the event&hellip; 

  9.         OnShapeChanged(new MyEventsArgs(&hellip;)); 

  10.         // or do something after the event.  

  11.     } 

  12.     protected virtual void OnShapeChanged(MyEventArgs e) 

  13.     { 

  14.         if(ShapeChanged != null) 

  15.         { 

  16.            ShapeChanged(this, e); 

  17.         } 

  18.     } 

  19. }

下面的示例演示如何处理以下的不常见情况:您的类是从两个以上的接口继承的,每个接口都含有同名事件)。在这种情况下,您至少要为其中一个事件提供显式接口实现。为事件编写显式接口实现时,必须编写  add 和 remove 事件访问器。这两个事件访问器通常由编译器提供,但在这种情况下编译器不能提供。

您可以提供自己的访问器,以便指定这两个事件是由您的类中的同一事件表示,还是由不同事件表示。例如,根据接口规范,如果事件应在不同时间引发,则可以将每个事件与类中的一个单独实现关联。在下面的示例中,订户将形状引用强制转换为  IShape 或 IDrawingObject,从而确定自己将会接收哪个 OnDraw 事件。

namespace WrapTwoInterfaceEvents {     using System;     public interface IDrawingObject     {         event EventHandler OnDraw;     }     public interface IShape     {         event EventHandler OnDraw;     }     public class Shape : IDrawingObject, IShape     {         event EventHandler PreDrawEvent;         event EventHandler PostDrawEvent;         event EventHandler IDrawingObject.OnDraw         {             add { PreDrawEvent += value; }             remove { PreDrawEvent -= value; }         }         event EventHandler IShape.OnDraw         {             add { PostDrawEvent += value; }             remove { PostDrawEvent -= value; }         }         public void Draw()         {             EventHandler handler = PreDrawEvent;             if (handler != null)             {                 handler(this, new EventArgs());             }             Console.WriteLine("Drawing a shape.");             handler = PostDrawEvent;             if (handler != null)             {                 handler(this, new EventArgs());             }         }     }     public class Subscriber1     {         public Subscriber1(Shape shape)         {             IDrawingObject d = (IDrawingObject)shape;             d.OnDraw += new EventHandler(d_OnDraw);         }         void d_OnDraw(object sender, EventArgs e)         {             Console.WriteLine("Sub1 receives the IDrawingObject event.");         }     }     public class Subscriber2     {         public Subscriber2(Shape shape)         {             IShape d = (IShape)shape;             d.OnDraw += new EventHandler(d_OnDraw);         }          void d_OnDraw(object sender, EventArgs e)         {             Console.WriteLine("Sub2 receives the IShape event.");         }     }     public class Program     {         static void Main(string[] args)         {             Shape shape = new Shape();             Subscriber1 sub = new Subscriber1(shape);             Subscriber2 sub2 = new Subscriber2(shape);             shape.Draw();              Console.WriteLine("Press Enter to close this window.");             Console.ReadLine();         }     } }

使用字典存储事件实例

accessor-declarations  的一种用法是公开大量的事件但不为每个事件分配字段,而是使用字典来存储这些事件实例。这只有在具有非常多的事件、但您预计大部分事件都不会实现时才有用。

  1. public delegate void EventHandler1(int i); 

  2. public delegate void EventHandler2(string s); 

  3. public class PropertyEventsSample 

  4.     private System.Collections.Generic.Dictionary<string, System.Delegate> eventTable; 

  5.     public PropertyEventsSample() 

  6.     { 

  7.         eventTable = new System.Collections.Generic.Dictionary<string, System.Delegate>(); 

  8.         eventTable.Add("Event1", null); 

  9.         eventTable.Add("Event2", null); 

  10.     } 

  11.     public event EventHandler1 Event1 

  12.     { 

  13.         add 

  14.         { 

  15.             eventTable["Event1"] = (EventHandler1)eventTable["Event1"] + value; 

  16.         } 

  17.         remove 

  18.         { 

  19.             eventTable["Event1"] = (EventHandler1)eventTable["Event1"] - value; 

  20.         } 

  21.     } 

  22.     public event EventHandler2 Event2 

  23.     { 

  24.         add 

  25.         { 

  26.             eventTable["Event2"] = (EventHandler2)eventTable["Event2"] + value; 

  27.         } 

  28.         remove 

  29.         { 

  30.             eventTable["Event2"] = (EventHandler2)eventTable["Event2"] - value; 

  31.         } 

  32.     } 

  33.     internal void RaiseEvent1(int i) 

  34.     { 

  35.         EventHandler1 handler1; 

  36.         if (null != (handler1 = (EventHandler1)eventTable["Event1"])) 

  37.         { 

  38.             handler1(i); 

  39.         } 

  40.     } 

  41.     internal void RaiseEvent2(string s) 

  42.     { 

  43.         EventHandler2 handler2; 

  44.         if (null != (handler2 = (EventHandler2)eventTable["Event2"])) 

  45.         { 

  46.             handler2(s); 

  47.         } 

  48.     } 

  49. public class TestClass 

  50.     public static void Delegate1Method(int i) 

  51.     { 

  52.         System.Console.WriteLine(i); 

  53.     } 

  54.     public static void Delegate2Method(string s) 

  55.     { 

  56.         System.Console.WriteLine(s); 

  57.     } 

  58.     static void Main() 

  59.     { 

  60.         PropertyEventsSample p = new PropertyEventsSample(); 

  61.  

  62.         p.Event1 += new EventHandler1(TestClass.Delegate1Method); 

  63.         p.Event1 += new EventHandler1(TestClass.Delegate1Method); 

  64.         p.Event1 -= new EventHandler1(TestClass.Delegate1Method); 

  65.         p.RaiseEvent1(2); 

  66.  

  67.         p.Event2 += new EventHandler2(TestClass.Delegate2Method); 

  68.         p.Event2 += new EventHandler2(TestClass.Delegate2Method); 

  69.         p.Event2 -= new EventHandler2(TestClass.Delegate2Method); 

  70.         p.RaiseEvent2("TestString"); 

  71.     } 

  72. }

事件的异步模式

有多种方式可向客户端代码公开异步功能。基于事件的异步模式为类规定了用于显示异步行为的建议方式。对于相对简单的多线程应用程序,BackgroundWorker  组件提供了一个简单的解决方案。对于更复杂的异步应用程序,请考虑实现一个符合基于事件的异步模式的类。

看完上述内容,你们对如何理解.Net事件有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

推荐阅读:
  1. 如何理解.NET Remoting
  2. .net回车事件

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

上一篇:mysql在linux上cmake如何安装

下一篇:Mysql数据分组排名实现的示例分析

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》