委托的调用方法与执行线程

    委托在C#中可以看作是对象的一种新类型。一般情况下,我们经常把数据作为参数传递给某个方法,但有时某个方法执行的操作并不是指对数据进行操作,而是要对另一个方法进行操作,这就需要使用委托了。

 

    委托典型的使用场合就是线程。当试图启动一个线程时,使用的Thread.Start()方法就必须带有一个参数,该参数包含了另一个方法的内容,即委托方法。

    委托的另一个场合就是事件,GUI编程主要是处理事件,比如Click事件是我们在应用程序中处理的,但是Windows是怎样知道调用应用程序的Click处理函数来响应Click事件的呢?这就是委托的作用。事件实际上是委托的一种特殊形式。

 

    如果从C++程序员的角度来理解,一个委托实例,可以理解成函数指针。但这种直接的函数指针调用会导致一些问题,比如类型的安全性,而且在面向对象的编程中,方法是无法孤立存在的,它通常需要与类实例相关联。所以,在C#中,就把这些方法包装在一种新类型的对象中,即委托。也就是说,委托其实是一种很特殊的对象类型(与类的概念一致)。所不同的是,以前定义的对象都可以包含数据,而委托却只包含方法签名。

 

一、定义委托

    定义委托,基本上是定义一个新类。你可以在定义类的任何地方定义委托,也可以在另一个类的内部定义一个委托。定义委托,其语法类似于定义一个方法,但没有方法体,定义的前面加上关键字delegate即可。

    delegate void MyDelegate(string sDescription);

如上就定义了一个带有string参数,无返回(void)的委托。任何具有这样签名格式的方法都可以看成是这个委托的一个实例,不管这个方法是任何对象上的实例方法或者是静态方法

 

二、委托的调用

    在调用委托之前,你需要先声明一个委托,并把它绑定到一个真正实现的方法上即可。

    private delegate void MyDelegate(string sDescription);

   

    static void OutPut(string sPara)

    {

        Console.WriteLine(sPara);

    }

 

    static void Main(string[] args)

    {

        //声明一个委托,并把OutPut当成是委托的一个实例

        MyDelegate  dlgt = new MyDelegate(OutPut);

        //直接调用委托

        dlgt("Call the delegate.");

    }

    于是程序输出结果"Call the delegate."。

    另一种委托的调用方式就是使用Invoke的形式来调用,当然两种调用结果是不一样的。

 

三、委托代码执行的所在线程

    委托代码执行所在的线程与调用方式相关,下面的例子说明了调用方式与执行线程的关系。

 

  //定义委托   delegate void MyDelegate(string sDesp);

 

  //委托实例   private void dlgtOutPut(string sDesp)   {

    Thread.Sleep(2000);

   //输出代码执行的线程名    Console.WriteLine(sDesp + ",Thread Name=" + Thread.CurrentThread.Name);   }

 

  private void ThreadEntity()   {    //设置子线程名称    Thread.CurrentThread.Name = "Child Thread";

 

   //实例化一个委托    MyDelegate dlgt = new MyDelegate(dlgtOutPut);    //    dlgtOutPut("直接调用委托");

 

   this.Invoke(dlgt,new object[]{("使用Invoke调用委托")});

   Console.WriteLine("After Invoke");   }   private void btnOK_Click(object sender, System.EventArgs e)   {    //设置主线程名称    Thread.CurrentThread.Name = "Main Thread";

 

   //启动线程    Thread thread = new Thread(new ThreadStart(ThreadEntity));    thread.Start();   }

 

程序的输出是:

    直接调用委托,Thread Name=Child Thread     使用Invoke调用委托,Thread Name=Main Thread     After Invoke

 

    可见,不同的调用方式,执行委托的线程也不一样。

    如果直接调用委托,则委托代码在子线程中执行;

    如果使用Invoke来调用委托,则发现委托代码则在主线程中执行。确切地说,当使用Invoke调用委托时,则在拥有此控件的基础窗口句柄的线程上执行委托。

 

四、同步与异步委托

    其实,从上面的例子可以看到,在委托中我们故意让委托Sleep(2000)。但发现"After Invoke"总是在委托的输出后面之后才输出。可见,不管是直接调用委托,还是使用Invoke调用委托的方式,都是同步的。第二种调用方式,从Windows程序的角度来看,其实就象是子线程向主线程使用SendMessage发送了一个消息,它需要最终等待消息返回,子线程才会继续执行。

    如果需要异步调用委托,则需要使用BeginInvoke的调用方式。现在我们修改上面的调用:

{

    ......

   IAsyncResult iAsync = this.BeginInvoke(dlgt, new object[]{"使用BeginInvoke调用委托"});    Console.WriteLine("After BeginInvoke");

 

   //等待委托执行完成    this.EndInvoke(iAsync);

}

    这次你会发现输出结果的顺序是:

    "After BeginInvoke"

    使用BeginInvoke调用委托,Thread Name=Main Thread

 

    所以,如果想要委托是异步执行的,就需要使用BeginInvoke来调用委托,并且异步委托也必须在拥有控件线程(示例中是主线程)上执行的。异步调用委托就象是向主线程使用PostMessage一样,它不必等待消息结果就返回了。

    可见,对于委托,调用方式的不同,不仅会决定了委托执行的线程,也决定了委托是否异步执行。

 

 

转自:http://blog.csdn.net/fsxdxh

posted @ 2015-11-02 16:16  Null98  阅读(403)  评论(0编辑  收藏  举报