zoukankan      html  css  js  c++  java
  • 委托, 匿名委托, Lambda表达式, 事件的本质, 以及Observer模式.

    1.委托的本质 

    委托实现了面向对象的,类型安全的方法回调机制。委托看上去就一句话, 很简单, 但在本质上它是一个类,CLR和编译器在后台会将委托自动编译为一个类.
    该类继承自System.MulticastDelegate类,该类维护一个委托列表,在调用多播委托时,将按照委托列表的委托顺序而调用的。该类包括一个接受两个参数的构造函数和3个重要方法:BeginInvoke、EndInvoke和Invoke。

    下面是delegate委托的父类MulticastDelegate的部分代码:

    public abstract class MulticastDelegate : Delegate
    {
      public sealed override Delegate[] GetInvocationList();
      // Overloaded operators.
      public static bool operator ==(MulticastDelegate d1, MulticastDelegate d2);
      public static bool operator !=(MulticastDelegate d1, MulticastDelegate d2);
      // Used internally to manage the list of methods maintained by the delegate.
      private IntPtr _invocationCount;
      private object _invocationList;
    }
    由此可以看出, 这个委托列表实际上就是一个Detegate类型的数组.

    另外, 委托声明放置的位置还要注意, 因为C#中允许出现嵌套类,而委托本质上就是一个类, 所以下面namespace1, namespace2两个方案都正确, 但namespace2的委托就成为了Class A的嵌套类.

    namespace namespace1


       public delegate void MyEventDelegate(int value);   
       public class A
       {

       }

    }


    namespace namespace2


       public class A
       {
            public delegate void MyEventDelegate(int value);   
       }

    }


    public class A
    {
         public class 委托
         {
         }
    }

    关于嵌套类的使用场合, 看到有帖子说就是如果A类中需要有某些代码需要以面向对象的形式展现,而又不想被除调用类以外的类调用到就可以使用嵌套类,需要注意的是嵌套类最好不要使用public访问符,因为这样无任何意义。
    如此一来, 建议将委托放置在其他类外面声明.


    一个完整的委托例子:

    namespace LatestWebTestSite
    {

      public delegate int DelegateAbc(int a, int b);
      public partial class _Default : System.Web.UI.Page
     {
       public int MethodAdd (int a, int b)
       {
         return a + b;
       }
       protected void Page_Load(object sender, EventArgs e)
       {
         DelegateAbc abc = MethodAdd;
         Response.Write(abc(100, 200));
       }
     }

    }


    2.匿名委托(方法)

    其实就是将方法定义与委托变量赋值两步并作一步了, 省了为方法起名了, 写起来省事而已.

    但编译后就知道了, 实际上编译器又将一步分作两步, 并给该方法起了个随机的名字, 匿名方法也就是个语法糖而已.

    button1.Click += delegate
       {
           MessageBox.Show("Hello world.");
        };

    3.Lambda表达式(=>)

    第一眼看到觉得是个很古怪的一个名字,有点排斥它。

    MSDN Lambda 表达式(http://msdn.microsoft.com/zh-cn/library/bb397687.aspx)上的定义: “Lambda 表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式树类型。

    所有 Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。 该 Lambda 运算符的左边是输入参数(如果有),右边包含表达式或语句块。 Lambda 表达式 x => x * x 读作“x goes to x times x”。可以将此表达式分配给委托类型.

    它是对匿名方法的进一步简化, 也是语法糖, 编译器会搞定将其一步步分开, 并起名的. Lambda表达式为LINQ提供了语法基础。

    来个例子如下:

        class Program
        {
            delegate void delgateLzd(int iValue);

            static void Main(string[] args)
            {
                delgateLzd del = x => {

                     Console.WriteLine(x * x);

                };

                del(5);

                Console.ReadKey();

            }       
        }

    比较一下即可知道, 这里面用的是Lambda语句,看上去酷似匿名方法,实际上就是用=>这个符号取代了匿名方法里的delegate这个单词,可以说是对匿名方法的又一次简化。

    原来想用委托要4步:1.定义委托,2.写一个符合委托的方法,3.建立委托实例并邦定刚才的方法, 4.调用委托。

    到了匿名方法这个阶段就把2,3两步给合并了,不用写独立的方法了,大大方便了委托的使用。

    而到了Lambda这里将匿名方法更进一步简化,连delegate都懒得写了,直接给个=>符号了事,如果需要参数就只把参数名列出来再接上=>,真是步步简化啊,到了这一步,如果是一个c#1的程序员穿越过来,看到这段代码,一定会大吃一惊,这里除了开始的委托类型以外,已经几乎看不到委托的影子了,但实际上,背地里,编译器还是给编译成了委托,这个语法糖是越来越甜,封装的越来越抽象了。

    4.事件的本质

    事件建立在委托之上,只有了解了委托才能明白事件的原理。事件是对委托的封装,从委托的示例中可知,在客户端可以随意对委托进行操作,一定程度上破坏了面向的对象的封装机制,因此事件实现了对委托的封装。
    事件其实就是委托类型的变量,也就是说如果想声明一个事件的话,你必须先声明一个委托类型的变量,然后将event关键字放在声明体的前部,例如:ITPUB个人空间M1iT/z m*FSV0x
    //声明事件委托
    public delegate void CalculateEventHandler(object sender,CalculateEventArgs e);
    //定义事件成员,提供外部绑定
    public event CalculateEventHandler MyCalculate;


    一个完整的事件例子:

    namespace UseEventExample
    {
        public delegate void MyEventDelegate(int value, int value2);

        class Program
        {
            public static void MethodAdd(int a, int b)
            {
                Console.WriteLine(a + b);
            }

            public static event MyEventDelegate abc; //定义一个事件

            static void Main(string[] args)
            {
                abc = MethodAdd;
                abc(100, 200);
                Console.ReadKey();

            }
        }
    }

    比较一下委托与事件的两个例子就可以比较出来,

    委托:DelegateAbc abc = MethodAdd;

    事件:Public static event MyEventDelegate abc;
             
    abc = MethodAdd;

    事件实际上就是委托的变量而已,它的作用就是提高委托的封装性。

    5.Observer模式

    使用委托和事件实现的观察者模式, 让观察者和被观察者不用任何耦合, 下面是猫叫鼠跑的例子代码:

    5.1 Cat

    namespace ConsoleApplication1
    {
        public delegate void CatDelegate ();

        public class Cat
        {
            public event CatDelegate catEvent;

            public void CatCry()
            {
                Console.WriteLine(" Cat is crying");

                 if (catEvent!=null)
                 {
                      catEvent();
                 }
            }

        }
    }

    5.2 Mouse

    namespace ConsoleApplication1
    {
        public class Mouse
        {
            public string MouseName { set; get; }

            public Mouse(string mouseName)
            {
                this.MouseName = mouseName;
            }

            public void run()
            {
                Console.WriteLine(MouseName + " start to run");
            }
        }
    }

    5.3 Main

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                Mouse mouse = new Mouse("mouse1");

                Cat cat = new Cat();
                cat.catEvent += mouse.run;
                cat.CatCry();

                Console.ReadKey();
            }
        }
    }

    当然, 正式的代码要抽象出observer, subject的接口, 然后让鼠, 猫分别实现之.

    作者:BobLiu
    邮箱:lzd_ren@hotmail.com
    出处:http://www.cnblogs.com/liuzhendong
    本文版权归作者所有,欢迎转载,未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    《Vue.js 2.x实践指南》 已出版
    《H5+移动应用实战开发》已出版
    关于《ASP.NET MVC企业级实战》
    ASP.NET MVC企业级实战目录
    ASP.NET MVC4入门到精通系列目录汇总
    网站服务架构
    ASP.NET MVC搭建项目后台UI框架—1、后台主框架
    webpack介绍—上
    通过一个vue+elementUI的小实例来讲解一下它们是如何使用的
    不要为自己学历低找借口
  • 原文地址:https://www.cnblogs.com/liuzhendong/p/2160953.html
Copyright © 2011-2022 走看看