zoukankan      html  css  js  c++  java
  • 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#编译器这时仍会保证类型安全。

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

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 排队打水问题
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    Java实现 蓝桥杯VIP 算法提高 特殊的质数肋骨
    现在使用控件, 更喜欢继承(覆盖控件已有的函数,很奇怪的一种使用方式)
    Controls 属性与继承 TShape 类的小练习(使用TShape可以解决很多图形问题)
    QT创建窗口程序、消息循环和WinMain函数(为主线程建立了一个QEventLoop,并执行exec函数)
  • 原文地址:https://www.cnblogs.com/longProgrammer/p/3192371.html
Copyright © 2011-2022 走看看