C# 事件进阶(第五章)

  我们可以对Car类型做最后一步改进,以符合asp.net里的事件模式。查看基类库中某个类型发送的事件时,会发同底层委托的第一个参数是一个System.Object,第二个参数是一个派生自System.Eventargs的类型。System.Object参数表示不念旧恶对发送事件的对象(例子如Car对象)的引用,第二个参数则表示与该事件相关的信息。System.Eventargs基类表示一个不发送任何自定义信息的事件:

public class EventArgs
{
    public static readonly System.EventArgs Empty;
    public EventArgs(){}
}

  对简单的事件来说,我们可以直接传递一个EventArgs实例。但如果要传递自定义数据,应该构建一个派生自EventArgs的类。在这个示例中,假定我们有一个名为CarEventArgs 的类,它保存一个字符串,表示要发送给接收者的信息:

public class CarEventArgs:EventArgs
{
    public static readonly string msg;
    public EventArgs(string message)
   {msg=message;}
}

  这样,我们就可以修改CarEventHandler委托了,如下所示(事件将保持不安):

public class Car
{ 
    
   public delegate void CarEventHandler(object sender,CarEventArgs e);
    ...
}

  当在Accelerate()方法中触发我们的事件时,需要提供对当前Car对象的一个引用和CarEventArgs类型的一个实例:

public void Accelerate(int delta)
    {
       if(carIsDead)
      {
          if(Exploded!=null)
          Exploded(this,new CarEventArgs("Sorry,this car is dead.."));
      }
     ...
}

  在调用者,我们要做的就是修改事件处理程序来接收传入的参数,并通过只读字段获取消息。例子如:

public static void CarAboutToBlow(object sender,CarEventArgs e)
   { Console.WriteLine("{0} says:{1}",sender,e.msg);
   }

   如果接收者想与发送事件的对象交互,我们可以显式强制类型转换System.Object。这样,如果要在Car对象将遇到它的创建者时“关闭广播”,可以创建一个如下所示的事件处理程序:

public static void CarIsAlmostDoomed(string msg)
   { 
     //安全起见,在强制类型转换前做一次运行时检查
     if(sender is Car)
     {
        Car c=(Car) sender;
        c.Cranktunes(false);
      }
      Console.WriteLine("Critical Message from {0}:{1}",sender,e.msg);
   }

   泛型EventHandler<T>委托

  由于很多自定义委托接受对象作为第一参数,EventArgs派生类型作为第二个参数,我们可以通过使用泛型EventHandler<T>类型来进一步简化之前的示例子,T就是自定义的EventArgs类型。

public calss Car
{
   public event EventHandler<CarEventArgs> Exploded;
   publci event EventHandler<CarEventArgs> AboutToBlow;
    ...
}
static void main(string[] args)
   {
     Console.Write("####Delegates as events ####
");
     Car cl=new Car("SlugBug",100,10);
    //注册事件处理程序
     cl.OnAboutToBlow +=new EventHandler<CarEventArgs>(CarIsAlmostDoomed);
     cl.OnAboutToBlow +=new EventHandler<CarEventArgs>(CarAboutToBlow);
     EventHandler<CarEventArgs d=new EventHandler<CarEventArgs>(CarExploded);
     c1.Exploded +=d;
     ...
   }

   C#匿名方法

  当一个调用者想监听传进来的事件时,它必须定义一个唯一的与相关联委托签名匹配的方法:

class Program
{
    static void Main(string[] args)
   {
     SomeType t=new SomeType();
     //假定"SomeDelegate"指向不带参数且无返回值的方法
    t.SomeEvent += new SomeDelegate(MyEventHandler);
   }
    //一般,它仅被SomeDelegate对象调用
   public static void MyEventHandler()
   {
     //事件触发时执行某些操作
   }
}

  稍微观察会发现,MyEventHandler()这样的方法很少会被调用委托之外的任保程序所调用。从生产效率的角度来说,手工定义一个由委托对象调用的方法显得有点繁锁,不会很受欢迎。
  为解决这一问题,现在可以在事件注册时直接将一个委托与一段代码相关联。这种代码的正名多称为匿名方法

class Pragram
{
 static void main(string[] args)
   {
     Console.Write("####Anonymous Methods ####
");
     Car cl=new Car("SlugBug",100,10);
    //注册事件处理程序为匿名方法
     cl.OnAboutToBlow +=delegate(object sender,CarEventArgs e)
        {    Console.WriteLine("Eek! Going too fast!");
        };
      cl.OnAboutToBlow +=delegate(object sender,CarEventArgs e)
        {    Console.WriteLine("Message from Car:{0}",e.msg);
        };
       cl.Exploded+=delegate(object sender,CarEventArgs e)
        {    Console.WriteLine("Fatal Message from Car:{0}",e.msg);
        };
       ...
   }
}

   方法组转换

public class SimpleMath
{
    public delegate void MathMessage(string msg);
    public event MathMessage ComputationFinished;
    public int Add(int x,int y)
    {
       ComputationFinshed("AddingComplete");
       return x+y;
    }
}

//如不用匿名方法,可以如下所示处理ComputationComplete事件
class Program
{
    static void Main(string[] args)
    {
       SimpleMath m=new SimpleMath();
       m.ComputationFinish +=new SimpleMath.MathMessage(ComputationFinishedHandler);
       Console.WriteLine("10+10 is{0}",m.Add(10,10));
       Console.ReadLine();
    }
    static void ComputationFinishedHandler(string msg)
    {
       Console.WriteLine(msg);
     }
}

  然而,我们可以用一个特定的事件来注册事件处理程序:
m.Computationfinished +=ComputationFinishedHandler;

  请注意,我们没有直接新建关联的委托类型,而是简单指定了一个匹配委托预期签名的方法,在本例中这个方法传入一个System.String而且没有返回值。要知道C#编译器这时仍会保证类型安全。

  显式转换一个事件处理程序为期关联委托的一个实例也是可能的。

原文地址:https://www.cnblogs.com/longProgrammer/p/3192371.html