zoukankan      html  css  js  c++  java
  • 细说委托

    在正式介绍委托之前,我想下看看生活中委托的例子——生活中,如果我们需要打官司,在法庭上是由律师为我们辩护的,然而律师执行的是当事人的陈词,这时候律师就是一个委托对象,当事人委托律师这个对象去帮自己辩护。这就是我们生活中委托的例子的。然而C#中委托的概念也就好比律师对象(从中可以得出委托是一个类,因为只有类才有对象的概念,从而也体现了C#是面向对象的语言)。 
    介绍完生活中委托是个什么后,现在就看看C#中的委托怎样和生活中的对象联系起来的,C#中的委托相当于C++中的函数指针(如果之前学过C++就知道函数指针是个什么概念的了),函数指针是用指针获取一个函数的入口地址,然后通过这个指针来实现对函数的操作。C#中的委托相当于C++中的函数指针,也就说两者是有区别的:委托是面向对象的,类型安全的,是引用类型(开始就说了委托是个类),所以在使用委托时首先要 声明委托类型——>有一个方法包含了执行的代码——>创建一个委托实例——>调用该委托实例。下面就具体看下如何使用委托的: 
    1、 声明委托类型,委托被声明为: 
    public delegate void AddDelete (int a,int b); 上述代码指出,如果要创建AddDelete的一个实例,需要带两个参数(两个都是int 类型)的方法,而且该方法需要有一个 void返回类型(该方法什么都不返回)。 2、 有一个方法包含了执行的代码 
    public static void Add(int a, int b) 
            { 
                Console.WriteLine(a+b);         } 
    3、 创建一个委托实例 
    AddDelete _adddelete = new AddDelete(Add); 
    创建委托实例,使用了new 关键字,说明委托也是类,将方法名Add作为参数绑定到该委托实例,也就是将方法Add指派给AddDelete委托,并将该引用赋给_adddelete对象,也就表示_adddelete对象保存了指向Add方法的引用,以此实现了对Add的回调。由此可见,委托表示了对其回调方法的签名,可以将方法当做参数进行传递,并根据传入的方法来动态的改变方法调用,只要为委托提供相同的签名的方法,都可以与委托绑定。 4、 调用该委托实例 
    _adddelete(1, 2); 
     完整代码如下: 
        class Program     { 
            public delegate void AddDelete(int a,int b);         static void Main(string[] args)         { 
                //创建委托实例,使用了new 关键字,说明委托也是类,将方法名Add作为参数绑定到该委托实例             AddDelete _adddelete = new AddDelete(Add); 

    //调用委托实例             _adddelete(1, 2);             Console.ReadLine();         }  
            public static void Add(int a, int b)         { 
                Console.WriteLine(a+b);         } 

    坦白讲,如果仅仅是为了显示上述a+b的输出,也没有必须使用委托,那么为什么不直接调用方法呢?答案存在于我们最开始的那个让律师来帮当事人辩护的例子中,不能仅仅由于当事人需要打官司这件事件发生,就意味着当事人懂法律,有时候,你需要给出一些指令(比如我需要打官司),将职责委托给别人(比如律师)。 
    应该强调的一点的时候,在软件世界中,没有对象 “打官司”这样的事情发生,经常都会发现这种情况,委托实例被调用时,最初创建委托实例的对象仍然存在的,也就是该对象自己也写一个打官司的方法,而委托相当于指定一些代码在特定的时间执行,那时,你也许已经无法(或者不想)更改要执行的代码,比如张三想打官司,直接调用已经存在的方法,并不想在张三对象内部重新写该方法,委托的实质就是间接完成某种操作,许多面向对象编程技术都在做同样的事情,我们看到,这增大了复杂性(看看为了输出a+b这点事,用了多少代码),但是同时也增加了灵活性。 
    相信通过上面两部分大家也明白了委托是个什么东西以及C#中为什么要引入委托这个概念。现在就总结下引入委托后到底作用在那里的? 从上面的委托代码中可以发现,引入委托后,编程人员可以把方法的引用封装在委托对象中(把过程的调用转化为对象的调用,充分体现了委托加强了面向对象编程的思想。),然后把委托对象传递给需要引用方法的代码,这样在编译的过程中我们并不知道调用了哪个方法,这样一来,C#引入委托机制后,使得方法声明和方法实现的分离,充分体现了面向对象的编程思想。 
    匿名方法 
    匿名方法就是没有名字的方法(函数),既然没有名字,就是说只有在定义的时候能调用,在其他地方就不能调用了(没有名字啊,那就找不到嘛)。为什么要用到匿名方法呢?调用函数是需要花销的,但有时候调用的一些方法很短小(例如一句话方法)、只完成很少的功能,这个时候就有点得不偿失了,此时就可以定义一个匿名方法来完成这个功能了,而匿名方法作为内联代码,花销相对小很多。匿名方法都是和委托连在一起用的(以后还有lambda表达式),以前创建委托实例时需要传递一个函数名给它作为参数,现在可以通过匿名方法直接把一段代码传进去了。 
    定义匿名方法:用到delegate关键字,如:delegate(int a, int b){return a > b ? a : b }   代码定义了一个匿名方法,该方法的参数是 int a 和 int b ,方法体是 {return a > b ? a : b}。如果只是定义一个匿名方法没有意义,因为定义完过后你就再也不能用这个匿名方法,所以匿名方法要在定义的时候就马上使用。一般来说就是初始化委托了。 
    上面 a+b 的例子 如何使用匿名方法,如下,可以看到这样就不需要再定义一个Add函数了, 
        class Program     { 
            public delegate void AddDelete(int a,int b);         static void Main(string[] args) 


                //创建委托实例,使用了new 关键字,说明委托也是类,将方法名Add作为参数绑定到该委托实例             AddDelete _adddelete = delegate(int a, int b) { Console.WriteLine(a + b); };             //调用委托实例             _adddelete(1, 2);             Console.ReadLine();         }  
        } 
    委托在Winform中的使用 
    1、如下所示, 如你所见,我现在创建了一个简陋的Form,其中放置了一个Lable控件lable1,一个Button控件button1,下面,开始code: 
     
     
            private void button1_Click(object sender, EventArgs e)         { 
                //新建一个线程,该线程调用test方法             Thread t1 = new Thread(test);             t1.Start();         }  
            public void test()         { 
                MethodInvoker mi = delegate() { 
                    this.label1.Text = "子线程中也可以显示我";             }; 
                label1.BeginInvoke(mi);         } 
    使用了BeginInvoke,我们查看BeginInvoke 的定义:可知,该方法传入的参数是 Delegate 回调方法,也就是 BeginInvoke 回调了一个委托方法,该方法具体实现由开发者自己写。  
     
     
    而 winform 本身声明了一个 委托类型 MethodInvoker 
    namespace System.Windows.Forms

     

     

        // 摘要:  
        //     表示一个委托,该委托可执行托管代码中声明为 void 且不接受任何参数的任何方法。     public delegate void MethodInvoker(); }      
    所以,我们调用 BeginInvoke的时候,可以让他执行 一个匿名方法  
                MethodInvoker mi = delegate() { 
                    this.label1.Text = "子线程中也可以显示我";             }; 
                label1.BeginInvoke(mi); 
     
    当然,我们也可以这样写  
                label1.BeginInvoke((MethodInvoker)delegate()             { 
                    this.label1.Text = "子线程中也可以显示我";             });  
    那么 我们 自己声明一个 委托 可以吗?当然也是可以的。 
    public delegate void Methodq(); 
    然后调用 使用  
                label1.BeginInvoke((Methodq)delegate()             { 
                    this.label1.Text = "子线程中也可以显示我";             });  
    我们回头再看看 BeginInvoke 的定义,他是public class Control 类中的一个方法,一个返回类型为
    IAsyncResult,传入参数为委托  
    public IAsyncResult BeginInvoke(Delegate method);   
    而 IAsyncResult 又是做什么的?查看定义如下,IAsyncResult为一个一步操作的接口,下一节课,将详细讲解,异步编程。  
        // 摘要:  
        //     表示异步操作的状态。     [ComVisible(true)] 
        public interface IAsyncResult


            // 摘要:  
            //     获取用户定义的对象,它限定或包含关于异步操作的信息。         // 
            // 返回结果:  
            //     用户定义的对象,它限定或包含关于异步操作的信息。         object AsyncState { get; }         //         // 摘要:  
            //     获取用于等待异步操作完成的 System.Threading.WaitHandle。         // 
            // 返回结果:  
            //     用于等待异步操作完成的 System.Threading.WaitHandle。         WaitHandle AsyncWaitHandle { get; }         //         // 摘要:  
            //     获取一个值,该值指示异步操作是否同步完成。         // 
            // 返回结果:  
            //     如果异步操作同步完成,则为 true;否则为 false。         bool CompletedSynchronously { get; }         //         // 摘要:  
            //     获取一个值,该值指示异步操作是否已完成。         // 
            // 返回结果:  
            //     如果操作完成则为 true,否则为 false。         bool IsCompleted { get; }     } 

    转载自:http://wenku.baidu.com/link?url=G0cQBAziuoxCTg2U4EgGHbQX500tNwHGgLJ-nvrz4Vs0jhsfaXEkFqxhS95AkJkkQSC3ZOm7NToI3Tes1xbh-2u8HAb6ZeAWjuAylIbJHN3

  • 相关阅读:
    SM2实现(利用openssl的evp)
    BouncyCastle的SM实践
    初步动态分析
    信安保障复习
    数据库实验3
    软件测试之测试用例设计题
    Spring SPI 机制总结
    Servlet与Netty横向对比
    被遮挡部分高亮
    (十一)Android环境变量设置
  • 原文地址:https://www.cnblogs.com/lxxhome/p/5567753.html
Copyright © 2011-2022 走看看