跳转到内容

.NET 开发基金会/使用事件

来自维基教科书,开放的书籍,开放的世界


系统类型和集合:使用事件和委托


使用事件和委托

[编辑 | 编辑源代码]

考试目标:通过使用事件和委托来控制 .NET Framework 应用程序组件之间的交互。

(参考 System 命名空间)

委托类 - MSDN

委托保存指向一个或多个函数的指针,并在需要时调用它们。
委托的一种常见用法是用于事件处理。引发事件的类不知道哪些对象或方法想要接收该事件,因此需要在引发事件的对象和接收事件的对象之间建立一个中介或指针机制。委托可以用作函数指针来完成此操作。
委托是一个类,但与普通类不同,它有一个签名。在 .Net 框架中,您只需声明委托,CLR 就会处理类的实现。
   //delegate declaration
   public delegate void AlarmEventHandler(object sender,EventArgs e);
第一个完整的示例只是声明一个委托类型,然后声明该类型的变量,将一个函数分配给它并执行委托变量,这将执行该函数。
C# 示例

简单的委托

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab01
   {
       // declare the delegate type
       public delegate int IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Assign the delegate
               IntOperDel deleg = pgm.Increment;
               // Executing the delegate
               int res = deleg(32);
               Console.WriteLine("First value: " + res.ToString());
               // Second assign
               deleg = pgm.Decrement;
               // Second execution
               res = deleg(32);
               Console.WriteLine("First value: " + res.ToString());
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to the delegate
           public int Increment(int n)
           {
               return n + 1;
           }
           // Second function to be assigned to the delegate
           public int Decrement(int n)
           {
               return n - 1;
           }
       }
   }
第二个委托示例实现了回调函数的概念。一个函数用委托作为参数调用。当它执行委托时,它不知道到底执行了什么函数。它的部分行为被委托给了作为参数传递的函数(通过委托)。
C# 示例

回调委托

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab02
   {
       // declare the delegate type
       public delegate int IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Assign the delegate
               IntOperDel deleg = pgm.Increment;
               // Calling a function that will execute de delegate
               // as part of its own logic
               pgm.ExecuteCallBack(deleg);
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // Function to be assigned to a delegate
           public int Increment(int n)
           {
               return n + 1;
           }
           // Function called with a delegate as parameter
           public void ExecuteCallBack(IntOperDel deleg)
           {
               int res = deleg(32);
               Console.WriteLine("Result from executing the callback: " + res.ToString());
           }
       }
   }
第三个委托示例使用委托成员来产生与事件相同的模式。请注意,在没有至少分配一个函数的情况下执行委托成员将导致异常。此外,使用 += 运算符分配 2 个函数将在执行委托时执行 2 个函数。如果委托具有返回值,则将返回最后执行的函数的返回值。
C# 示例

委托成员

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab03
   {
       // declare the delegate type
       public delegate void IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(int n)
           {
               int res = n + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(int n)
           {
               int res = n - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member of the delegate type
           public IntOperDel delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               this.delMember(32);
           }
       }
   }
第四个示例是事件的基本示例。它与第三个示例完全相同,只是在成员声明中添加了event关键字,并在调用事件之前进行了测试,因为“空”事件会引发异常。此示例清楚地表明事件只不过是一个多播委托。
C# 示例

事件成员

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace DelegateLab04
   {
       // declare the delegate type
       public delegate void IntOperDel(int i);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(int n)
           {
               int res = n + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(int n)
           {
               int res = n - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event IntOperDel delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(32);
           }
       }
   }
执行与事件关联的函数称为引发事件。
与事件关联的函数称为事件处理程序

EventArgs 类 - MSDN

按照惯例,事件使用一个返回 void 并接受 2 个参数的委托
  • 一个 System.Object 类型的对象,其中包含对引发事件的对象的引用。
  • 来自从 EventArgs 派生的类的对象,其中包含从引发事件的对象传递给事件处理程序的数据。
EventArgs 类本身不包含任何数据。
因此,没有数据的事件将使用以下形式的委托
public delegate void DelegateTypeName (object sender, EventArgs e)
这个简单的事件示例与上一个示例相同,使用 IntEventArgs 类将 int 参数传递给事件处理程序,并且所有参数都已更改以遵循事件的调用约定。
C# 示例

具有遵循调用约定的委托的事件

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace EventLab01
   {
       // the class containing the event data passed to the event handler
       public class IntEventData : EventArgs
       {
           public int IntParm = 0;
           // constructor
           public IntEventData(int i)
           {
               IntParm = i;
           }
       }
       // the delegate type
       public delegate void IntOperDel(object sender, IntEventData e);
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(object sender, IntEventData e)
           {
               int res = e.IntParm + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(object sender, IntEventData e)
           {
               int res = e.IntParm - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event IntOperDel delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(this, new IntEventData(32));
           }
       }
   }

EventHandler 委托 - MSDNMSDN

System 命名空间中定义了两个特殊的委托来帮助您进行事件声明。
第一个是 EventHandler 委托。它不传递任何数据。不传递任何数据的事件可以声明为
public event EventHandler EventName
无需声明自定义委托。
这是声明不传递任何数据的事件的通常方式。
C# 示例

使用 EventHandler 委托的事件

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace EventLab03
   {
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to the event
           public void Increment(object sender, EventArgs e)
           {
               int res = 32 + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to the event
           public void Decrement(object sender, EventArgs e)
           {
               int res = 32 - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event EventHandler delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(this, null);
           }
       }
   }
第二个是 EventHandler<T> 通用委托,其中 T 是从 EventArgs 派生的类型
public event EventHandler<T> EventName
同样不需要声明自定义委托类型。
这是声明将数据传递给事件处理程序的事件的通常方式。
请注意,在这种情况下,您仍然需要声明从 EventArgs 派生的类型 T。
C# 示例

利用 EventHandler<T> 的事件

   using System;
   using System.Collections.Generic;
   using System.Text;
   //
   namespace EventLab02
   {
       // the class containing the event data passed to the event handler
       public class IntEventData : EventArgs
       {
           public int IntParm = 0;
           // constructor
           public IntEventData(int i)
           {
               IntParm = i;
           }
       }
       //
       class Program
       {
           static void Main(string[] args)
           {
               Program pgm = new Program();
               // Use += oper to assign functions to the delegate
               pgm.delMember += pgm.Increment;
               pgm.delMember += pgm.Decrement;
               // Calling some member function that will execute the delegate
               pgm.ExecuteSomething();
               // Wait for finish
               Console.WriteLine("Press ENTER to finish");
               Console.ReadLine();
           }
           // First function to be assigned to a delegate
           public void Increment(object sender, IntEventData e)
           {
               int res = e.IntParm + 1;
               Console.WriteLine("Inside increment function: " + res.ToString());
           }
           // Second function to be assigned to a delegate
           public void Decrement(object sender, IntEventData e)
           {
               int res = e.IntParm - 1;
               Console.WriteLine("Inside decrement function: " + res.ToString());
           }
           // Class member event of the delegate type
           public event EventHandler<IntEventData> delMember;
           // Function called to execute the delegate member (raise the "event")
           public void ExecuteSomething()
           {
               if (this.delMember != null)
                   this.delMember(this, new IntEventData(32));
           }
       }
   }
这总结了事件和委托的基本示例。
华夏公益教科书