细说委托

在正式介绍委托之前,我想下看看生活中委托的例子——生活中,如果我们需要打官司,在法庭上是由律师为我们辩护的,然而律师执行的是当事人的陈词,这时候律师就是一个委托对象,当事人委托律师这个对象去帮自己辩护。这就是我们生活中委托的例子的。然而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

时间: 2024-10-06 13:40:30

细说委托的相关文章

【C#复习总结】细说委托

1 前言 前几天看到博客园一个前辈写了一篇文章用“五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树”,文章写的非常好,推荐阅读一下,正所谓“前人栽树,后人乘凉”,在这我就站在巨人的肩上,再将这几个概念加上“事件”这一概念在复习一遍,一来是加深记忆,二来方便后来人学习,本人小白一枚,有错的地方希望老司机指正. 2 什么是委托 委托是一个类,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序

【C#复习总结】细说泛型委托

1 前言 本系列会将[委托] [匿名方法][Lambda表达式] [泛型委托] [表达式树] [事件]等基础知识总结一下.(本人小白一枚,有错误的地方希望大佬指正) 系类1:细说委托 系类2:细说匿名方法 系列3:细说Lambda表达式 系列4:细说泛型委托 系列5:细说表达式树 系列6:细说事件 还是用大佬的文章来震场吧,“随着.net版本的不升级,新版本总要区别于旧版本吧,不然微软的工程师怎么向他们的老大交差呀?所以微软又来玩新花样了.” 这次我们提前贴代码来体验一下泛型委托与一般委托和匿名

【C#复习总结】细说表达式树

1 前言 系类1:细说委托 系类2:细说匿名方法 系列3:细说Lambda表达式 系列4:细说泛型委托 系列5:细说表达式树 系列6:细说事件 涛声依旧,再续前言,接着用大佬的文章作为开头. 表达式树其实与委托已经没什么关系了,非要扯上关系,那就这么说吧,表达式树是存放委托的容器.如果非要说的更专业一些,表达式树是存取Lambda表达式的一种数据结构.要用Lambda表达式的时候,直接从表达式中获取出来,Compile()就可以直接用了.如下代码: using System; using Sys

匹夫细说C#:庖丁解牛聊委托,那些编译器藏的和U3D给的

0x00 前言 由于工作繁忙所以距离上一篇博客已经过去一个多月的时间了,因此决心这个周末无论如何也得写点东西出来,既是总结也是分享.那么本文主要的内容集中在了委托的使用以及内部结构(当然还有事件了,但是受制于篇幅故分为两篇文章)以及结合一部分Unity3D的设计思考.当然由于时间仓促,文中难免有一些疏漏和不准确,也欢迎各位指出,共同进步. 0x01 从观察者模式说起 在设计模式中,有一种我们常常会用到的设计模式——观察者模式.那么这种设计模式和我们的主题“如何在Unity3D中使用委托”有什么关

[转]C#综合揭秘——细说多线程(上)

C#综合揭秘——细说多线程(上) 引言 本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发.其中委托的BeginInvoke方法以及回调函数最为常用.而 I/O线程可能容易遭到大家的忽略,其实在开发多线程系统,更应该多留意I/O线程的操作.特别是在ASP.NET开发当中,可能更多人只会留意在客户端使用Ajax或者在服务器端使用UpdatePanel.其实合理使用I/O线程在通讯项目或文件下载时,能尽可能地减少IIS的压力.并行编程

[转载]C#深入分析委托与事件

原文出处: 作者:风尘浪子 原文链接:http://www.cnblogs.com/leslies2/archive/2012/03/22/2389318.html 同类链接:http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html 引言 本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C# 当中事件(Event)的由来,它能使处理委托类型的过程变得更加简单.还将为您解释委托的协变与逆变,以及如何使用 Deleg

C#综合揭秘——深入分析委托与事件

本篇文章将为你介绍一下 Delegate 的使用方式,逐渐揭开 C# 当中事件(Event)的由来,它能使处理委托类型的过程变得更加简单.还将为您解释委托的协变与逆变,以及如何使用 Delegate 使 Observer(观察者)模式的使用变得更加简单.在事件的介绍上,会讲述事件的使用方式,并以ASP.NET的用户控件为例子,介绍一下自定义事件的使用.最后一节,将介绍Predicate<T>.Action<T>.Func<T,TResult>多种泛型委托的使用和Lamb

细说.NET 中的多线程 (一 概念)

为什么使用多线程 使用户界面能够随时相应用户输入 当某个应用程序在进行大量运算时候,为了保证应用程序能够随时相应客户的输入,这个时候我们往往需要让大量运算和相应用户输入这两个行为在不同的线程中进行. 效率原因 应用程序经常需要等待一些资源,如等待网络资源,等待io资源,等待用户输入等等.这种情况下使用多线程可以避免CPU长时间处于闲置状态. 用户态,内核态 线程内的资源有两种运行态,即用户态和内核态.某些运算可以在堆栈上进行,这种情况线程是在用户态运行的,某些需要高权限运行的指令,或者某些优先级

【转】C#综合揭秘——细说多线程(上)

C#综合揭秘——细说多线程(上) 风尘浪子 只要肯努力,梦想总有一天会实现 引言 本文主要从线程的基础用法,CLR线程池当中工作者线程与I/O线程的开发,并行操作PLINQ等多个方面介绍多线程的开发.其中委托的BeginInvoke方法以及回调函数最为常用.而 I/O线程可能容易遭到大家的忽略,其实在开发多线程系统,更应该多留意I/O线程的操作.特别是在ASP.NET开发当中,可能更多人只会留意在客户端 使用Ajax或者在服务器端使用UpdatePanel.其实合理使用I/O线程在通讯项目或文件