iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C#中Invoke的用法讲解
  • 394
分享到

C#中Invoke的用法讲解

2024-04-02 19:04:59 394人浏览 安东尼
摘要

C#中Invoke的用法() invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些

C#中Invoke的用法()

invoke和begininvoke 区别

一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解。

首先说下,invoke和begininvoke的使用有两种情况:

1. control中的invoke、begininvoke。

2. delegrate中的invoke、begininvoke。

这两种情况是不同的,我们这里要讲的是第1种。下面我们在来说下.net中对invoke和begininvoke的官方定义。

control.invoke(参数delegate)方法:在拥有此控件的基础窗口句柄的线程上执行指定的委托。

control.begininvoke(参数delegate)方法:在创建控件的基础句柄所在线程上异步执行指定委托。

根据这两个概念我们大致理解invoke表是同步、begininvoke表示异步。

如果你的后台线程在更新一个UI控件的状态后不需要等待,而是要继续往下处理,那么你就应该使用BeginInvoke来进行异步处理。

如果你的后台线程需要操作UI控件,并且需要等到该操作执行完毕才能继续执行,那么你就应该使用Invoke。

我们来做一个测试

invoke 例子:


private void button1_Click(object sender, EventArgs e)
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA");
            invokeThread = new Thread(new ThreadStart(StartMethod));
            invokeThread.Start();
            string a = string.Empty;
            for (int i = 0; i < 3; i++)      //调整循环次数,看的会更清楚
            {
                Thread.Sleep(1000);   
                a = a + "B";
            }
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a);
}

 private void StartMethod()
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC");
            button1.Invoke(new invokeDelegate(invokeMethod));  
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD");
}

 private void invokeMethod()
{
            //Thread.Sleep(3000);
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEE");
}

结论:我们运行后,看下程序的运行顺序,1AAA->3CCC和1BBB->1EEE ->3DDD 。

解释:主线程运行1AAA,然后1BBB和子线程3CCC同时执行,然后通过invoke来将invokemethod方法提交给主线程,然后子线 程等待主线程执行,直到主线程将invokemethod方法执行完成(期间必须等待主线程的任务执行完成,才会去执行invoke提交的任务),最后执 行子线程3DDD。

begininvoke 例子:


private void button1_Click(object sender, EventArgs e)
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA");
            invokeThread = new Thread(new ThreadStart(StartMethod));
            invokeThread.Start();
            string a = string.Empty;
            for (int i = 0; i < 3; i++)      //调整循环次数,看的会更清楚
            {
                Thread.Sleep(1000);   
                a = a + "B";
            }
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a);
}

 private void StartMethod()
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC");
            button1.BeginInvoke(new invokeDelegate(invokeMethod));  
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD");
}

 private void beginInvokeMethod()
        {
            //Thread.Sleep(3000);
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEEEEEEEEEEE");
        }

结论: 我们运行后看看执行的结果:1AAA->1BBB和3CCC->1EEE和3DDD。

解释: 主线程运行1AAA,然后1BBB和子线程3CCC同时执行,然后通过begininvoke来将invokemethod方法提交给主线程,然后主线程执行1EEE(主线程自己的任务执行完成), 同时子线程继续执行3DDD。

通过这个两段代码的测试比较,我们会发现其实invoke和begininvoke所提交的委托方法都是在主线程中执行的,其实根据我invoke 和begininvoke的定义我们要在子线程中来看这个问题,在invoke例子中我们会发现invoke所提交的委托方法执行完成后,才能继续执行 DDD;在begininvoke例子中我们会发现begininvoke所提交的委托方法后,子线程讲继续执行DDD,不需要等待委托方法的完成。 那么现在我们在回想下invoke(同步)和begininvoke(异步)的概念,其实它们所说的意思是相对于子线程而言的,其实对于控件的调用总是由 主线程来执行的。我们很多人搞不清这个同步和异步,主要还是因为我们把参照物选错了。其实有时候光看概念是很容易理解错误的。

解决从不是创建控件的线程访问它

多线程编程中,我们经常要在工作线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的做法,Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。

正确的做法是将工作线程中涉及更新界面的代码封装为一个方法,通过 Invoke 或者 BeginInvoke 去调用,两者的区别就是一个导致工作线程等待,而另外一个则不会。

而所谓的“一面响应操作,一面添加节点”永远只能是相对的,使 UI 线程的负担不至于太大而已,因为界面的正确更新始终要通过 UI 线程去做,我们要做的事情是在工作线程中包揽大部分的运算,而将对纯粹的界面更新放到 UI 线程中去做,这样也就达到了减轻 UI 线程负担的目的了。

举个简单例子说明下使用方法,比如你在启动一个线程,在线程的方法中想更新窗体中的一个TextBox..


using System.Threading; 

//启动一个线程 
Thread thread=new Thread(new ThreadStart(DoWork)); 
thread.Start(); 

//线程方法 
private void DoWork() 
{ 
this.TextBox1.Text="我是一个文本框"; 
} 

如果你像上面操作,在VS2005或2008里是会有异常的... 

正确的做法是用Invoke\BeginInvoke

using System.Threading;
namespace test
{
public partial class FORM1 : Form
{
public delegate void MyInvoke(string str1,string str2);
public Form1()
{
InitializeComponent();


}
public void DoWork()
{
MyInvoke mi = new MyInvoke(UpdateForm);
this.BeginInvoke(mi, new Object[] {"我是文本框","haha"});
}
public void UpdateForm(string param1,string parm2)
{
this.textBox1.Text = param1+parm2;
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
}
}
}

注意代理的使用!

后面再次补充 在 winform开发过程中经常会用到线程,有时候还往往需要在线程中访问线程外的控件,比如:设置textbox的Text属性等等。如果直接设置程序必 定会报出:从不是创建控件的线程访问它,这个异常。通常我们可以采用两种方法来解决。一是通过设置control的属性。二是通过delegate,而通 过delegate也有两种方式,一种是常用的方式,另一种就是匿名方式。下面分别加以说明.

首先,通过设置control的一个属性值为false.我们可以在Form_Load方法中添加:Control.CheckForIllegalCrossThreadCalls=false;来解决。设置为false表示不对错误线程的调用进行捕获。这样在线程中对textbox的Text属性进行设置时就不会再报错了。

其次,通过delegate的方法来解决。

普通的委托方法例如:


delegate void SafeSetText(string strMsg);
private void SetText(string strMsg)
{
 if(textbox1.InvokeRequired)
 {
            SafeSetText objset=new SafeSetText(SetText);
            textbox1.Invoke(objSet,new object[]{strMsg});

 }
 else
 {
   textbox1.Text=strMsg;
 }
}

在线程内需要设置textbox的值时调用SetText方法既可。我们还可以采用另一种委托的方式来实现,那就是匿名代理,例如:


delegate void SafeSetText(string strMsg);
private void SetText2(string strMsg)
{
  SafeSetText objSet = delegate(string str)
   {
       textBox1.Text = str;
   }
   textBox1.Invoke(objSet,new object[]{strMsg});
}

这样同样可以实现。

个人觉得还是采用代理好些。

在C# 3.0及以后的版本中有了Lamda表达式,像上面这种匿名委托有了更简洁的写法。.NET Framework 3.5及以后版本更能用Action封装方法。例如以下写法可以看上去非常简洁:


void ButtonOnClick(object sender,EventArgs e)
{
    this.Invoke(new Action(()=>
    {
        button.Text="关闭";
    }));
}

最新:


Invoke(() =>
{
 button.Text="关闭";
});

到此这篇关于C#中Invoke的用法讲解的文章就介绍到这了,更多相关C# Invoke内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C#中Invoke的用法讲解

本文链接: https://www.lsjlt.com/news/130037.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C#中Invoke的用法讲解
    C#中Invoke的用法() invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些...
    99+
    2022-11-12
  • C# Invoke,begininvoke的用法详解
    在C#中,Invoke和BeginInvoke是用于在多线程编程中调用委托的方法。委托是一种可以存储对方法的引用的类型,可以用于异步...
    99+
    2023-08-08
    C#
  • C#中Invoke的用法是什么
    这篇文章主要介绍“C#中Invoke的用法是什么”,在日常操作中,相信很多人在C#中Invoke的用法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#中Invoke的用法是什么”的疑惑有所帮助!接下来...
    99+
    2023-06-20
  • c#中Invoke与BeginInvoke的用法及说明
    目录c# Invoke与BeginInvoke先讲下InvokeBeginInvoke总结c# Invoke与BeginInvoke 最近在学习线程时,发现当我创建的线程需要访问UI...
    99+
    2023-01-28
    c# Invoke c# BeginInvoke c# Invoke与BeginInvoke
  • 关于C#中的Invoke示例详解
    目录C# 关于Invoke什么时候用?为什么要用1、Control的Invoke2、Delegate的Invoke怎么用?1、Control 的 Invoke2、Delegate的I...
    99+
    2023-02-06
    c#的invoke c#中invoke方法详解 c# Invoke
  • C#的Invoke怎么使用
    在C#中,Invoke是用于在主线程中执行委托的方法。Invoke方法可以确保委托在主线程上同步执行,这在多线程编程中非常有用。以下...
    99+
    2023-08-08
    C# Invoke
  • 详解Java中Method的Invoke方法
    在写代码的时候,发现从父类class通过getDeclaredMethod获取的Method可以调用子类的对象,而子类改写了这个方法,从子类class通过getDeclaredMethod也能获取到Method,这时去调用父类的对象也会报错...
    99+
    2023-05-31
    java method invoke
  • C#中怎么调用P/Invoke
    C#中怎么调用P/Invoke,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。C#调用P/Invoke是完成这一任务的最常用方法。要C#调用P/Invoke,您可以编写一个描...
    99+
    2023-06-17
  • c# invoke方法怎么正确使用
    在C#中,可以使用Invoke方法来在另一个线程中执行UI操作。以下是正确使用Invoke方法的步骤。 确保你正在在UI线程中调用...
    99+
    2023-10-28
    c#
  • C#中的==运算符用法讲解
    目录==运算符与基元类型==运算符与引用类型==运算符与String类型==运算符与值类型==运算符与泛型总结==运算符与基元类型 我们分别用两种方式比较两个整数,第一个使用的是Eq...
    99+
    2022-11-13
  • C++中list的用法实例讲解
    目录前言一、list的节点二、list的迭代器2.1、模板参数为什么是三个2.2 const 迭代器2.3 修改方法二、美中不足三、迭代器的分类3.x std::find的一个报错总...
    99+
    2022-11-12
  • C/C++举例讲解关键字的用法
    目录staticstatic修饰全局变量static修饰局部变量static修饰函数constBOOLbreakcontinuestatic static修饰全局变量 static修...
    99+
    2022-11-13
  • 深入解析Java中反射中的invoke()方法
    先讲一下java中的反射: 反射就是将类别的各个组成部分进行剖析,可以得到每个组成部分,就可以对每一部分进行操作 反射机制应用场景:逆向代码、动态生成类框架等,使用反射机制能够大大的...
    99+
    2022-11-12
  • C#中怎么用invoke获取返回值
    在C#中可以使用Invoke方法来调用一个方法或委托,并获取其返回值。Invoke方法是Delegate类的成员,可以用于调用任何类...
    99+
    2023-10-23
    C# invoke
  • C语言详细讲解const的用法
    目录一、int const a / const int a二、const int(*p)/int const(*p)三、int*const p四、const用于函数的地址传递参数一、...
    99+
    2022-11-13
  • C#中Parallel类For、ForEach和Invoke使用介绍
    一、简介: Parallel类提供了数据和任务的并行性;Paraller.For()方法类似于C#的for循环语句,也是多次执行一个任务。使用Paraller.For()方法,可以并...
    99+
    2022-11-13
  • c语言中enum类型的用法案例讲解
    11.10 枚举类型 在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,一个班每周有六门课程等等。如果把这些量说明为整型,字符型或其它...
    99+
    2022-11-12
  • C++ STL 中的数值算法示例讲解
    目录1.iota2.accumulate3.partial_sum4.adjacent_difference5.inner_product以下算法均包含在头文件 numeric 中 ...
    99+
    2022-11-13
  • C#中执行SQL的几种方法讲解
    1.不同的数据库 private InfoLightDBTools dbTools; //#ORACLE# this.dbTools = new InfoLightDBT...
    99+
    2022-11-13
  • C语言 socketpair用法案例讲解
    socketpair()函数的声明: #include <sys/types.h> #include <sys/socket.h> int socketp...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作