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#编译器这时仍会保证类型安全。

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

  • 相关阅读:
    Ubuntu18.04+windows10双系统时间同步教程
    Ubuntu官方源
    Ubuntu 16.04下OLSR协议安装教程
    Ubuntu 18.04中的Vim编辑器的高级配置
    关于vue-cli的安装
    var与let、const的区别
    jq点击相册弹出弹窗并可以轮播相册效果
    css三角形上下左右实心空心尖角箭头
    leetcode-44. Wildcard Matching
    c++转换构造函数和类型转换函数
  • 原文地址:https://www.cnblogs.com/longProgrammer/p/3192371.html
Copyright © 2011-2022 走看看