一、invoke和BeginInvoke的作用
invoke和begininvoke方法的初衷是为了解决在某个非某个控件创建的线程中刷新该控件可能会引发异常的问题。说的可能比较拗口,举个例子:主线程中存在一个文本控件,在一个子线程中要改变该文本的值,此时会有可能引发异常。windows GUI编程有一个规则,就是只能通过创建控件的线程来操作控件的数据,否则就可能产生不可预料的结果。
二者的使用情况有两种:
1.在控件下应用,实例类型是个control例如button等;
2.在委托下进行使用,实例对象是一个委托类型,在使用时候会跳到当前线程。
invoke和begininvoke的区别:
1、Invoke() 调用时,Invoke会阻止当前主线程的运行,等到 Invoke() 方法返回才继续执行后面的代码,表现出“同步”的概念。
2、BeginInvoke() 调用时,当前线程会启用线程池中的某个线程来执行此方法,BeginInvoke不会阻止当前主线程的运行,而是等当前主线程做完事情之后再执行BeginInvoke中的代码内容,表现出“异步”的概念。在想获取 BeginInvoke() 执行完毕后的结果时,调用EndInvoke() 方法来获取。而这两个方法中执行的是一个委托。
二、Invke用法示例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace 线程test1005 { public delegate void test(string s1); class Program { static void Main(string[] args) { test tt = new test(t1); Thread thread = new Thread(() => { tt.Invoke("你好"); }); thread.Start(); string obj = Thread.CurrentThread.ManagedThreadId.ToString(); Console.WriteLine("主线程的ID" + " :" + obj); Console.Read(); } static void t1(string s1) { string obj = Thread.CurrentThread.ManagedThreadId.ToString(); Console.WriteLine(s1+"支线程的ID" +" :"+obj); } }
三、BeginInvoke用法示例
invoke和begininvoke对比:
1.invoke用法:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace 线程test1005 { public delegate void test(string s1); class Program { static void Main(string[] args) { test tt = new test(t1); tt.Invoke("你好"); for (int i = 0; i < 300; i++) { Console.Write(3); } Console.Read(); } static void t1(string s1) { for (int i = 0; i < 300; i++) { Console.Write(2); } string obj = Thread.CurrentThread.ManagedThreadId.ToString(); Console.WriteLine(s1+"支线程的ID" +" :"+obj); } } }
由结果可以看出invoke是依次按顺序向下执行;
2.beginInvoke用法:
首先介绍一下begininvoke的参数,其中作重要的就是后两个参数这里使用了BeginInvoke方法的最后两个参数,如果被调用的方法含有参数的话,这些参数将作为BeginInvoke的前面一部分参数,(就是 传入调用方法的参数)如果没有参数,BeginInvoke就只有两个参数。第一个参数是回调方法委托类型,这个委托只有一个参数,就是IAsyncResult,如MethodCompleted方法所示。当method方法执行完后,系统会自动调用MethodCompleted方法,传入的其实也是调用方法的返回类型,BeginInvoke的第二个参数需要向MethodCompleted方法中传递一些值,一般可以传递被调用方法的委托类型。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace 线程test1005 { public delegate void test(string s1); class Program { static void Main(string[] args) { test tt = new test(t1); tt.BeginInvoke("111", (a) => { for (int i = 0; i < 300; i++) { Console.Write(1); } }, null); for (int i = 0; i < 300; i++) { Console.Write(3); } Console.Read(); } static void t1(string s1) { for (int i = 0; i < 300; i++) { Console.Write(2); } string obj = Thread.CurrentThread.ManagedThreadId.ToString(); Console.WriteLine(s1+"支线程的ID" +" :"+obj); } } }
由运行结果可以知道,begininvoke可以继续执行调用方法后的函数,关于begininvoke的具体用法可以参考该文章:Delegate的BeginInvoke()_begininvoke参数-CSDN博客
例子:
static void Main(string[] args) { Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主 线程ID SayHello sayhello = new SayHello(Say); IAsyncResult iResult=sayhello.BeginInvoke("Olive",new AsyncCallback(Result), sayhello);//三个参数:1、Say()函数的参数,2、AsyncCallback类型的委托,(异步操作结束后执行的委托函数),3、将sayhello对象作为状态参数,在Result函数中会有用到该参数 Console.ReadKey(); } //AsyncCallback委托所执行的函数 private static void Result(IAsyncResult iasyncresult) { SayHello sayhello = (SayHello)iasyncresult.AsyncState;//获取IAsyncResult对象的AsyncState的属性,即为Delegate.BeginInvoke()的第三个参数即sayhello。 string s = sayhello.EndInvoke(iasyncresult); Console.WriteLine(s + "------好了,异步调用到这里已经结束了"); } private static string Say(string name) { Console.WriteLine("Hello!--------" + name); Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId); return "I Love you " + name; }
提示:1.begininvoke的返回值类型为IAsyncResult ,并且返回值会继续作为参数传入后续的AsyncCallback回调函数中Result。
2.函数的实际返回值需要通过EndInvoke进行获取!