委托

委托

(C#类)

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。

 

委托初识

编辑
我们知道委托是一个引用类型,所以它具有引用类型所具有的通性。它保存的不是实际值,而是保存对存储在托管堆(managed heap)中的对象的引用。那它保存的是对什么的引用呢?委托保存的是对函数(function)的引用
 
 

委托初识

编辑
我们知道委托是一个引用类型,所以它具有引用类型所具有的通性。它保存的不是实际值,而是保存对存储在托管堆(managed heap)中的对象的引用。那它保存的是对什么的引用呢?委托保存的是对函数(function)的引用。
对学过C/C++的人,是不是觉得跟函数指针很像呢!委托可以引用实例和静态(在 Visual Basic 中为 Shared)方法,而函数指针只能引用静态(在 Visual Basic 中为 Shared)方法。 其实它们是有区别的,在非托管C/C++中,函数的地址就是一个内存地址。该地址不会携带任何额外的信息,例如函数期望的参数个数、参数类型、函数的返回值类型及函数的调用约定。总之,非托管C/C++中函数指针是非类型安全的。而.NET中的委托是类型安全的,委托会检测它所保存的函数引用是否和声明的委托匹配。
 
 

委托类

编辑
当我们用delegate关键字声明委托时,编译器自动为我们生成类。类的名字即为委托变量名,访问类型为定义的委托访问类型。如上例中,public delegate void CallBack(string name, int number);定义的委托对应的类为CallBack,访问类型为public,该类继承自[mscorlib]System.MulticastDelegate。如果我们定义委托的访问类型为private或者protected,则对应的委托类的访问类型为private或者protected。但是任何委托都继承自[mscorlib]System.MulticastDelegate。
什么是委托
首先要知道什么是委托,用最通俗易懂的话来讲,你就可以把委托看成是用来执行方法(函数)的一个东西。
如何使用委托
在使用委托的时候,你可以像对待一个类一样对待它。即先声明,再实例化。只是有点不同,类在实例化之后叫对象或实例,但委托在实例化后仍叫委托

 

刚学习委托时无论老师怎么开导,我都是一头雾水,不是听不懂,也不是不会写,就是不明白为什么要用委托,看不出来一点好处,而且写很多没用的代码,每当这么问老师时,老师总说:用委托会使你的代码更灵活,我的天啊,和没说一样,后来参加工作了两年竟然一直没有用到委托也没什么觉得不妥,直到有一天看到了张子阳的“事件和委托”让我大吃一惊研读了几天终于弄懂了一点事件和委托,这时突然感觉以前写的程序都不是程序,起码不是面向对象的程序,因为事件和委托是面向对象编程精髓。

     上几天一个同事问我什么是委托,我告诉他:“委托是方法的指针,可以把方法当参数用......,懂么?”,他说懂了。他又问我为啥要用委托不用不行么我依然可以实现委托能实现的任何功能,这时我想像我老师一样的告诉他,他肯定会和我一样迷糊2年,于是我给他出了一道题:实现一个能定时做某事的类就像winform的timer一样的东西,他实现的代码如下:

 public class Timer
{
public static void start(int sleep)
{
  ThreadStart ts = new ThreadStart(DoSomething);
  Thread th = new Thread(ts);
  th.Start();
}
/// <summary>循环做事
/// </summary>
public static void DoSomething()
{
  while (true)
  {
  writeFile();
  Thread.Sleep(1000);//线程休眠1秒
}
}
/// <summary>写文件
/// </summary>
public static void writeFile()
{
  System.IO.StreamWriter sw = new System.IO.StreamWriter("path");
  sw.Write("ok");
  sw.Close();
  sw.Dispose();
}
}

 

恩,很快就实现了,可以1秒钟写一次文件,那我要一秒钟向数据库插入一条记录呢?于是他修改代码如下:

public class Timer

{
   public static int doType = 0;
   public static void start(int sleep)
   {
    ThreadStart ts = new ThreadStart(DoSomething);
    Thread th = new Thread(ts);
    h.Start();
   }
        /// <summary>循环做事
        /// </summary>
        public static void DoSomething()
        {
            while (true)
            {
                if (doType == 0)
                    writeFile();
                else if(doType==1)
                    InsertDB();
                Thread.Sleep(1000);//线程休眠1秒
            }
        }
        /// <summary>写文件
        /// </summary>
        public static void writeFile()
        {
            System.IO.StreamWriter sw = new System.IO.StreamWriter("path");
            sw.Write("ok");
            sw.Close();
            sw.Dispose();
        }
        public static void InsertDB()
        {
            //写数据库
        }
 
}
 
这不是很容易么?你要做啥事都行,我只要加分支判断就可以了。我问他:先不说你这些代码是否符合“开闭原则”和"单一职责原则",就说你这代码别人要怎么使用,拷过去添加一个方法再添加一个分支判断?你起码提取一下做个通用类,像winform的timer一样别人只要传给你两个参数1.间隔时间,2.要做的事,剩下就是你的事了。于是他又修改了代码:
public class Timer
{
    public static void start(int sleep, ? doSomething)
    {
 
    }
}
他写到这说:不会写了,我不知道doSomething应该是啥类型,他是别人传给我要执行的方法。我告诉他doSomething的类型就应该是一个委托,委托适合用在某时或某种情况执行某些事,而这些事你事先并不知道是啥。就像本例中,你想间隔1秒钟替别人执行某件事,但你设计这个类的这个方法时还不知道别人到底要你做什么事。用现实生活中的示例做比喻:一个律师能替人打官司,他可以打任何类型的官司,但只有原告委托律师打官司时律师才知道自己要打什么类型的官司,所以律师就是一个委托。好了下面我们来看一下我实现的Timer类:
 
 
public class Timer
{
  public delegate void TimerHandler();
  public static void start(int sleep, TimerHandler doSomething)
  {
    ThreadStart ts = new ThreadStart(() => { while (true) { Thread.Sleep(sleep); doSomething(); } });
    Thread th = new Thread(ts);
    th.Start();
  }
}
由于当时我正在学习匿名方法和Lambda所以ThreadStart参数用Lambda代替了具体的函数。
 
 
委托可以理解为:将一些有相同特征的函数(参数个数,参数类型)抽象成一个公用的委托,委托其实可以认为是这些相同特征函数的一个别名。
1、调用这些函数组中的某一个函数时,只要实例化出这样的一个委托对象,通过这个委托对象传入相应的参数即可实现调用原函数的目的。
2、多路广播委托,委托对象的绑定

static void Main(string[] args)
{

GetTest test = new GetTest(A);
test += new GetTest(B);
test();

Console.Read();
}

public delegate int GetTest();

public static int A()
{
Console.WriteLine("A");
return 1;
}
public static int B()
{
Console.WriteLine("B");
return 1;
}

 
 
 
 

 

posted on 2017-04-05 23:27  zjone391  阅读(111)  评论(0编辑  收藏  举报