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

 

    委托在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一样,它不必等待消息结果就返回了。

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

 

 

 

 
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
异步委托线程调用控件是指在多线程的情况下,通过使用异步委托来实现对控件的跨线程调用。这种方法可以解决在线程访问控件时可能出现的界面卡死、无响应等问题。 在C#,可以通过使用Invoke或BeginInvoke方法来实现异步委托线程调用控件。使用Invoke方法可以确保任务在线程执行,而BeginInvoke方法允许任务在后台线程执行。具体的使用方法如下: 1. 在线程创建委托方法,该方法用于更新控件的属性或执行其他与控件相关的操作。 2. 当需要在后台线程更新控件时,使用Invoke或BeginInvoke方法,将委托方法作为参数传递给它们。 3. 在委托方法,通过控件的Invoke方法或BeginInvoke方法来更新控件。 请注意,为了避免线程冲突和不可预料的结果,强烈不推荐使用Control.CheckForIllegalCrossThreadCalls = false;这种方法。相反,应该采用合理的方法,即在线程负责UI界面的调度,将耗时的操作放在后台线程进行,并使用Invoke委托来触发UI刷新。这样可以确保界面的稳定性和响应性,避免出现卡死、无响应或报错等问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [C#跨线程调用控件](https://blog.csdn.net/tonghaojie/article/details/78767046)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [C# winform delegate委托以及异步调用委托(跨线程调用控件UI)使用总结](https://blog.csdn.net/gxlzhhx/article/details/128568462)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值