本文转载自
1 . 委托的定义: 委托是函数的封装,它代表一 " 类 " 函数. 他们都符合一定的签名:拥有相同的参数列表,返回值类型.同时,委托也可以看成是对函数的抽象,是函数的 " 类 " .此时,委托的实例将代表一个具体的函数. 委托声明和定义了一个引用类型,它用来封装方法,用指定的签名来封装方法.一个委托的实例,可以封装静态或者实例方法. 委托是一种引用的类型,一旦为委托分配了方法,委托将与该方法完全相同的行为,委托方法的使用可以像其他任何方法一样, 具有参数和返回值 委托的一个特征是它们的类型是安全的.可以确保被调用的方法签名是正确的,但他们并不关心调用该方法的是什么类型的对象,甚至不考虑该方法是静态方法还是实例方法.(给定委托的实例可以表示任何类型的任何对象上的实例方法或静态方法,只要方法的签名匹配于委托的签名就可以). 2 . 委托的使用: 当要把方法传递给其他方法时,需要使用委托. 为什么什么用委托: 更加灵活的方法调用. 用于异步回调. 多线程编程中使用委托来定启动一个线程时调用的方法. C#中的事件模型,用他们来指明处理给定事件的方法. 例: class Program { // 定义委托 delegate double ProcessDelegate( double param1, double param2); static double Multiply( double param1, double param2) { return param1 * param2; } static double Divide( double param1, double param2) { return param1 / param2; } static void Main( string [] args) { // 定义委托变量 ProcessDelegate pd; double param1 = 20 ; double param2 = 10 ; Console.WriteLine( " Enter M to multiply or D to divide " ); string input = Console.ReadLine(); if (input == " M " ) { // 初始化委托变量,要把一个函数引用赋给委托变量, // 参数是要使用的函数名,且不带括号. pd = new ProcessDelegate(Multiply); } else { pd = new ProcessDelegate(Divide); } // 使用该委托调用所选函数 Console.WriteLine( " Result: {0} " ,pd(param1,param2)); Console.ReadKey(); } 3 . 多播委托: 引用多个方法的委托,它连续调用每个方法. 为了把委托的单个实例合并为一个多播委托,委托必须是同类型的,返回类型必须是void,不能带输出参数out(可以带引用参数ref). 多播委托应用于事件模型中. // 声明委托 public delegate void myDelegate(); public partial class Form1 : Form { public Form1() { InitializeComponent(); } public void aa() { Console.WriteLine( " aa " ); } public void bb() { Console.WriteLine( " bb " ); } public void cc() { Console.WriteLine( " cc " ); } myDelegate md; private void button1_Click( object sender, EventArgs e) { md = new myDelegate(aa); md += new myDelegate(bb); myDelegate m = new myDelegate(cc); md += m ; md(); } } 4 . 异步回调: 由于实例化委托是一个对象,所以可以将其作为参数进行传递.也可以将其赋值给属性.这样,方法便可以将一个委托作为参数来接受,并且以后可以调用该委托.这样称为异步回调,是在较长的进程完成后用来通知调用方的常用方法.以这种方式使用委托时,使用委托的代码无需了解有关所用方法的实现方面的任何信息. 回调的另一个常见用法是定义自定义的比较方法并将该委托传递给排序方法. 例: // 定义委托 delegate void Del( int a, int b); class Program { static void Main( string [] args) { Program p = new Program(); Del d = new Del(p.F_min); // 实例化委托并传给他比较的方法. p.CallBack( 10 , 30 , d); // 调用回调函数 } // 回调函数,将委托实例作为方法参数进行传递. public void CallBack( int a, int b,Del d) { d(a, b); // 执行委托 } // 输出较大的数 public void F_max( int a, int b) { Console.WriteLine( " 大的那个数为: " + Math.Max(a,b)); } // 输出较小的数 } 5 . 匿名方法 匿名方法允许我们以一种”内联”的方式来编写方法代码,将代码直接与委托实例相关联,从而使得委托实例化的工作更加直观和方便. 使用例子: class Program{ // 定义委托 public delegate string dTest( string val); static void Main( string [] args){ string mid = " 男子足球队 " ; // 匿名方法 dTest aDelegate = delegate ( string param){ param += mid; param += " 加油. " ; return param; }; Console.WriteLine(aDelegate( " 中国 " )); Console.ReadLine(); } } 如果委托类型的返回类型为void,匿名方法里便不能返回任何值.如果不为void,匿名方法里返回的值必须和委托类型的返回值兼容. 6 . 何时使用委托,何时接口 ? 委托: 当使用事件设计模式时. 当封装静态方法可取时. 当调用方不需要访问实现该方法的对象中的其他属性方法或接口时. 需要方便的组合. 当类可能需要该方法的多个实现时. 接口: 当存在一组可能被调用的相关方法时. 当类只需要方法的单个实现时. 当使用接口的类想要将该接口强制转换为其他接口或类类型时. public void F_min( int a, int b) { Console.WriteLine( " 小的那个数为: " + Math.Min(a,b)); }