• 浅谈委托、委托与事件、委托进化成lambda表达式和Linq


       委托的重要性,在C#中是不言而喻的,理解起来也需反复琢磨,初学者可能觉得很难,但是迈过去这套槛后,也许就觉得容易了。本文结合自己的体会,将从委托、委托与事件、委托进化成lambda表达式,再到linq,浅谈自己的理解与体会,与大家交流交流,还望高手多多指点。真的很佩服微软这帮牛逼的人,一环套一环的设计,不知他们刚开始设计C#委托时是否就想到了未来将要产生的linq技术。

      我们先从单纯的委托开始研究。MSDN上给委托定义为:委托是一种定义方法签名的类型。 当实例化委托时,您可以将其实例与任何具有兼容签名的方法相关联。 您可以通过委托实例调用方法。 这三句话的意思表明了委托是一种类型,但是一种很特殊的类型,包含参数,返回值,一般类前面会有一个class修饰,但是委托前面用delegate;在实例化委托这个类型时需要与一个具体的方法相关联,而且这个方法的参数,返回值必须与委托定义的参数和返回值类型、个数一致。考虑现实中的一个现象,大贪官一般不自己索贿,会通过他的助手或者其他人间接索贿,这里贪官和他的助手之间会形成一个委托关系,大贪官可以定义成一个委托,助手索贿可以定义为一种方法。

         这里面为了方便先定义个贪官类、助手类、贪官委托

    namespace testcsharp3._0
    {
        public delegate void EventHandler();//大贪官委托,不包含任何参数,返回值为空
        class tanguan //大贪官类,里面还什么也没有
        {    }
    }

    namespace testcsharp3._0
    {

        class zhushou   //定义助手类,里面包含一个静态方法,注意方法的参数和返回值与贪官的委托兼容
        {
            public static void suohui()
            {
                Console.WriteLine("贪官要出去旅游,通过助手帮其索贿1000元!");        
            }
        }
    }

     static void Main(string[] args)
            {
                tanguan tg = new tanguan();//实力化一个贪官类
                EventHandler weituo = new EventHandler(zhushou.suohui);//实例化一个委托,与zhushou类中的suohui方法关联起来
                weituo();//执行委托
                Console.ReadLine();

            }

    运行结果:贪官要出去旅游,通过助手帮其索贿1000元!

    到此个最简单的委托例子就实现了,当然这个例子没有任何用处,呵呵。大家注意到,上面索贿这个动作实际上是通过main()函数里面的weituo()执行的。可能还是需要贪官给助手提示,助手才去索贿,这样的助手显然是不合理的。情况应该是一旦贪官缺钱花(这个事情发生可能使随机的),助手就要帮其去索贿,这样子贪官才会喜欢。与我们编程中点击一个按钮控件,就会触发一个事件一样。因此为了改进这种贪官的需求,我们有必要引入事件机制,一旦缺钱花的事件发生,助手就开始行动,呵呵!

     class tanguan
        {
            public delegate void EventHandler();//大贪官委托,不包含任何参数,返回值为空 
            public event EventHandler nomoney;//贪官缺钱事件,与官的委托联系起来

            public void nomoneyhappen()  
            {
                nomoney();//触发这个缺钱事件
            }
        }

     static void Main(string[] args)
            {
                 tanguan tg = new tanguan();//实力化一个贪官类
                 tg.nomoney += new tanguan.EventHandler(tg_nomoney);//注册一个缺钱的事件
                tg.nomoneyhappen();//执行函数,引发缺钱事件发生
                Console.ReadLine();

            }

            static void tg_nomoney()//缺钱事件发生后,要干的事情
            {
                zhushou.suohui();//调用助手来要钱
            }

    运行后输出:贪官要出去旅游,通过助手帮其索贿1000元!

     上面的代码就是将事件与委托联系起来了,但是这样的时间没有任何的参数传递,假如一个助手要帮好几个官处理要钱的事情,他必须知道是谁缺钱了,当他要到钱后就可以给谁,所以这种情况下,触发的事件对象应该清楚。

            public string tanguanname { get; set; }//给贪官这个类加个名字属性,便于助手找
            public delegate void NameEventHandler(object sender, EventArgs e);//大贪官委托,包含一个object的参数和空的EventArgs参数,sender就是引起事件的对象
            public event NameEventHandler namenomoney;

            public void nomoneyhappen() 
            {
                //触发这个缺钱事件
                namenomoney(this, null);//传递当前对象过去
            }

     static void Main(string[] args)
            {
                tanguan tg = new tanguan() {tanguanname="A" };//实力化一个A贪官类       
                tg.namenomoney += new tanguan.NameEventHandler(tg_namenomoney); //注册一个缺钱的事件
                tg.nomoneyhappen();//执行函数,引发缺钱事件发生
                Console.ReadLine();

            }

            static void tg_namenomoney(object sender, EventArgs e)
            {
                tanguan t = sender as tanguan;//获得到底是哪个官缺钱
                Console.WriteLine(t.tanguanname);
                zhushou.suohui();
            }

    上面的运行输出为:A  贪官要出去旅游,通过助手帮其索贿1000元!

    如果把main()函数中的 tanguan tg = new tanguan() {tanguanname="B" };//实力化一个B贪官类  ,那么结果就是 B  贪官要出去旅游,通过助手帮其索贿1000元!

    同样的如果想传递更多参数信息,我们可以继承EventArgs类,定义自己的参数类型,这样传递的信息会更丰富哦! 

    通过上面的事件与委托代码 我们知道程序流程是:先定义一个委托,接着定义一个委托的事件,在调用方里面注册一个事件,并实例化一个委托,与这个注册的事件关联起来,定义委托的方法,在方法中执行你想要干的事情。 一旦我们触发了事件(这里我们通过代码触发的,像button这样的标准控件可以通过鼠标点击触发),就会执行委托的方法。

     下面我们研究委托的进化。像上面那些注册事件的代码 tg.namenomoney += new tanguan.NameEventHandler(tg_namenomoney); //注册一个缺钱的事件

    发现这里的方法名称tg_namenomoney其实作用不大,C#中完全可以用匿名方法代替,因此代码可以改为

    tg.namenomoney += delegate(object sender, EventArgs e)//匿名方法
                {
                     tanguan t = sender as tanguan;//获得到底是哪个官缺钱
                Console.WriteLine(t.tanguanname);
                zhushou.suohui();

                };

    匿名方法的引用,让委托变得直接了当,不用绕个弯子了,至于 匿名方法编译成什么了,要研究下编译后的代码,这个还没仔细研究过,有待完善。。。

    微软那帮人觉得上面那样搞代码还不够简洁,如是又产生了lambda表达式

    tg.namenomoney += (object sender, EventArgs e)=>
                {
                 tanguan t = sender as tanguan;//获得到底是哪个官缺钱
                Console.WriteLine(t.tanguanname);
                zhushou.suohui();

                };

    这个和上面的执行结果一样。注意=>这个是在lambda里面产生的新的符号,左边表示参数列表,右边执行语句,lambda表达式的参数既可以是显示类型化的,也可以是隐式的。编译器可以更具上下文推断出来。在我看来 这些都是委托演变而来的,只不过微软把编译器做的更牛了,让我们少写了很多代码,编译器编译后的代码估计还原始的委托差不多(没有研究过,不知道对不对)

    有了lambda表达式后,微软又整出来个隐式类型的东东,我们经常说C#是强类型语言,任何变量的定义都必须指定类型,但是在现实中有一种这样的情况,我们需要的是数据,并不关注他的类型是什么,从数据库检索出来的数据,也许和某个实体类属性是一一对应的,但是我们并不需要所有这些字段的数据,我们可能利用其中的两个字段的数据,以前的搞法是,在新定义一个类型,然后一个个实例化这个类,赋值给属性。现在如果有了隐式类型,我们就可以省下从新定义类的工作量了。如:var peoplename=“huxing”; 编译器会自动的推断出这个变量的类型是字符串,说到底还是编译器干的活,牛逼!

    有了隐士类型,有了lambda表达式,微软就水到渠成的推出了Linq,先看下面这段代码

     public static List<person> listperson = new List<person>
            {
             new person{name="guoyuanwei",age=600},
             new person{name="wanjianbang",age=600},
             new person{name="xiaoyunxi",age=600},
             new person{name="huxing",age=600},
             new person{name="hujingtao",age=100},
             new person{name="wenjiabao",age=80},        
            };

            public static void showallperson(List<person> listp,int count)
            {
                     var man = from p in listp
                       where p.age > 300
                       select new { manname = p.name, manage = p.age };//lambda表达式,linq语句

             foreach(var v in man)
             {
                 Console.WriteLine(v.manname + ":" + v.manage.ToString());
             }

          }

     如果在main()函数里面调用showallperson()就会输出 年龄大于300的人的名字,如果采取传统的c#代码,我们可能这样做

     把 showallperson部分改为用foreach遍历
      public static void showallperson(List<person> listp,int count)
            {

           foreach (person p in listp)
             {
                 if(p.age>300)
                 Console.WriteLine(p.name + ":" + p.age.ToString());
             }

      }

    咋看上去代码还少些了,当然我的这个例子比较短,也许看不出啥来,但是在复杂的逻辑中lambda表达式就会显出他的威力。

    好了,就写到这里,要干活了哦,时间紧,任务重啊!下次在整理整理,写的不好,望大家指正。

  • 相关阅读:
    内存映射mmap的几个api及其使用
    hiredis的安装
    Linux 下解压大全
    redis内存数据库C客户端hiredis API 中文说明
    C/C++使用MySQL
    搜索引擎的缓存(cache)机制
    快速排序(QuickSort)
    冒泡排序
    spring核心之AOP学习总结一
    Spring学习总结六——SpringMVC一
  • 原文地址:https://www.cnblogs.com/guoyuanwei/p/2108658.html
Copyright © 2020-2023  润新知