C# 委托的三种调用示例(同步调用、异步调用、异步回调)
首先,通过代码定义一个委托和下面三个示例将要调用的方法:
代码如下:
- public delegate int AddHandler(int a,int b);
- public class 加法类
- {
- public static int Add(int a, int b)
- {
- Console.WriteLine("开始计算:" + a + "+" + b);
- Thread.Sleep(); //模拟该方法运行三秒
- Console.WriteLine("计算完成!");
- return a + b;
- }
- }
同步调用
委托的Invoke方法用来进行同步调用。同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。
代码如下:
- public class 同步调用
- {
- static void Main()
- {
- Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
- AddHandler handler = new AddHandler(加法类.Add);
- int result = handler.Invoke(, );
- Console.WriteLine("继续做别的事情。。。");
- Console.WriteLine(result);
- Console.ReadKey();
- }
- }
同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕的用户体验,这时候异步调用就很有必要了。
异步调用
异步调用不阻塞线程,而是把调用塞到线程池中,程序主线程或UI线程可以继续执行。委托的异步调用通过BeginInvoke和EndInvoke来实现。
代码如下:
- public class 异步调用
- {
- static void Main()
- {
- Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
- AddHandler handler = new AddHandler(加法类.Add);
- //IAsyncResult: 异步操作接口(interface)
- //BeginInvoke: 委托(delegate)的一个异步方法的开始
- IAsyncResult result = handler.BeginInvoke(, , null, null);
- Console.WriteLine("继续做别的事情。。。");
- //异步操作返回
- Console.WriteLine(handler.EndInvoke(result));
- Console.ReadKey();
- }
- }
可以看到,主线程并没有等待,而是直接向下运行了。但是问题依然存在,当主线程运行到EndInvoke时,如果这时调用没有结束(这种情况很可能出现),这时为了等待调用结果,线程依旧会被阻塞。
异步委托,也可以参考如下写法:
Action<object> action=(obj)=>method(obj);
action.BeginInvoke(obj,ar=>action.EndInvoke(ar),null);
简简单单两句话就可以完成一部操作。
异步回调
用回调函数,当调用结束时会自动调用回调函数,解决了为等待调用结果,而让线程依旧被阻塞的局面。
代码如下:
- public class 异步回调
- {
- static void Main()
- {
- Console.WriteLine("===== 异步回调 AsyncInvokeTest =====");
- AddHandler handler = new AddHandler(加法类.Add);
- //异步操作接口(注意BeginInvoke方法的不同!)
- IAsyncResult result = handler.BeginInvoke(,,new AsyncCallback(回调函数),"AsycState:OK");
- Console.WriteLine("继续做别的事情。。。");
- Console.ReadKey();
- }
- static void 回调函数(IAsyncResult result)
- {
- //result 是“加法类.Add()方法”的返回值
- //AsyncResult 是IAsyncResult接口的一个实现类,空间:System.Runtime.Remoting.Messaging
- //AsyncDelegate 属性可以强制转换为用户定义的委托的实际类。
- AddHandler handler = (AddHandler)((AsyncResult)result).AsyncDelegate;
- Console.WriteLine(handler.EndInvoke(result));
- Console.WriteLine(result.AsyncState);
- }
- }
我定义的委托的类型为AddHandler,则为了访问 AddHandler.EndInvoke,必须将异步委托强制转换为 AddHandler。可以在异步回调函数(类型为 AsyncCallback)中调用 MAddHandler.EndInvoke,以获取最初提交的 AddHandler.BeginInvoke 的结果。
问题:
(1)int result = handler.Invoke(1,2);
为什么Invoke的参数和返回值和AddHandler委托是一样的呢?
答:Invoke方法的参数很简单,一个委托,一个参数表(可选),而Invoke方法的主要功能就是帮助你在UI线程上调用委托所指定的方法。Invoke方法首先检查发出调用的线程(即当前线程)是不是UI线程,如果是,直接执行委托指向的方法,如果不是,它将切换到UI线程,然后执行委托指向的方法。不管当前线程是不是UI线程,Invoke都阻塞直到委托指向的方法执行完毕,然后切换回发出调用的线程(如果需要的话),返回。
所以Invoke方法的参数和返回值和调用他的委托应该是一致的。
(2)IAsyncResult result = handler.BeginInvoke(1,2,null,null);
BeginInvoke : 开始一个异步的请求,调用线程池中一个线程来执行,
返回IAsyncResult 对象(异步的核心). IAsyncResult 简单的说,他存储异步操作的状态信息的一个接口,也可以用他来结束当前异步。
注意: BeginInvoke和EndInvoke必须成对调用.即使不需要返回值,但EndInvoke还是必须调用,否则可能会造成内存泄漏。
(3)IAsyncResult.AsyncState 属性:
获取用户定义的对象,它限定或包含关于异步操作的信息。 例如:
代码如下:
- static void AddComplete(IAsyncResult result)
- {
- AddHandler handler = (AddHandler)result.AsyncState;
- Console.WriteLine(handler.EndInvoke(result));
- }
完整代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Runtime.Remoting.Messaging;
- namespace ConsoleTest
- {
- public delegate int AddHandler(int a,int b);
- public class 加法类
- {
- public static int Add(int a, int b)
- {
- Console.WriteLine("开始计算:" + a + "+" + b);
- Thread.Sleep(); //模拟该方法运行三秒
- Console.WriteLine("计算完成!");
- return a + b;
- }
- }
- public class 同步调用
- {
- static void Main()
- {
- Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
- AddHandler handler = new AddHandler(加法类.Add);
- int result = handler.Invoke(, );
- Console.WriteLine("继续做别的事情。。。");
- Console.WriteLine(result);
- Console.ReadKey();
- }
- }
- public class 异步调用
- {
- static void Main()
- {
- Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
- AddHandler handler = new AddHandler(加法类.Add);
- //IAsyncResult: 异步操作接口(interface)
- //BeginInvoke: 委托(delegate)的一个异步方法的开始
- IAsyncResult result = handler.BeginInvoke(, , null, null);
- Console.WriteLine("继续做别的事情。。。");
- //异步操作返回
- Console.WriteLine(handler.EndInvoke(result));
- Console.ReadKey();
- }
- }
- public class 异步回调
- {
- static void Main()
- {
- Console.WriteLine("===== 异步回调 AsyncInvokeTest =====");
- AddHandler handler = new AddHandler(加法类.Add);
- //异步操作接口(注意BeginInvoke方法的不同!)
- IAsyncResult result = handler.BeginInvoke(,,new AsyncCallback(回调函数),"AsycState:OK");
- Console.WriteLine("继续做别的事情。。。");
- Console.ReadKey();
- }
- static void 回调函数(IAsyncResult result)
- {
- //result 是“加法类.Add()方法”的返回值
- //AsyncResult 是IAsyncResult接口的一个实现类,引用空间:System.Runtime.Remoting.Messaging
- //AsyncDelegate 属性可以强制转换为用户定义的委托的实际类。
- AddHandler handler = (AddHandler)((AsyncResult)result).AsyncDelegate;
- Console.WriteLine(handler.EndInvoke(result));
- Console.WriteLine(result.AsyncState);
- }
- }
- }
*********转载:https://m.jb51.net/article/44093.htm
C# 委托的三种调用示例(同步调用、异步调用、异步回调)的更多相关文章
- C# 委托的三种调用示例(同步调用 异步调用 异步回调)
首先,通过代码定义一个委托和下面三个示例将要调用的方法: 复制代码 代码如下: public delegate int AddHandler(int a,int b); public class ...
- 20160711--C# 委托的三种调用示例(同步调用 异步调用 异步回调)【转载】
首先,通过代码定义一个委托和下面三个示例将要调用的方法: 代码如下: public delegate int AddHandler(int a,int b); public class 加法类 { p ...
- php发送post请求的三种方法示例
本文分享下php发送post请求的三种方法与示例代码,分别使用curl.file_get_content.fsocket来实现post提交数据,大家做个参考. php发送post请求的三种方法,分别使 ...
- unity 三种注入示例
/* * 演示Unity 注入 * */ using Microsoft.Practices.Unity; using System; namespace Unity.Property.Inject ...
- css渐变写法 从左到右渐变三种颜色示例;
background:linear-gradient(to right,#7f06a8,#a02bc2,#7f06a8)
- SpringBoot2.0.2 Application调用的三种方式
一.注解 @SpringBootApplication 点开查看源码是由多个注解合成的注解,其中主要的注解有: @SpringBootConfigurati ...
- C# 委托高级应用----线程——创建无阻塞的异步调用(一)
前言 本文大部分内容来自于mikeperetz的Asynchronous Method Invocation及本人的一些个人体会所得,希望对你有所帮助.原英文文献可以在codeproject中搜索到. ...
- 谈.Net委托与线程——创建无阻塞的异步调用(一)
前言 本文大部分内容来自于mikeperetz的Asynchronous Method Invocation及本人的一些个人体会所得,希望对你有所帮助.原英文文献可以在codeproject中搜索到. ...
- MySQL冗余数据的三种方案
一,为什么要冗余数据 互联网数据量很大的业务场景,往往数据库需要进行水平切分来降低单库数据量. 水平切分会有一个patition key,通过patition key的查询能够直接定位到库,但是非pa ...
随机推荐
- PHP数据结构之一:PHP数据结构基本概念—数据结构
学习任何一种技术都应该先清楚它的基本概念,这是学习任何知识的起点!本文是讲述数据结构的基本概念,适合对数据结构已经有一定基础的程序员,更是适合想要学习数据结构的code一族!让我们开始PHP数据结构的 ...
- sql数据库各个版本清除日志
SQL2005清空删除日志: 复制代码 代码如下: Backup Log DNName with no_log --'这里的DNName是你要收缩的数据库名,自己注意修改下面的数据 ...
- java基础之io流总结四:字符流读写
字符流读写只适用于字符文件. 基本字符流(转换流)读写文件 转换流本身是字符流,但是实例化的时候传进去的是一个字节流,所以叫做转换流 InputStreamReader isr = new Input ...
- CAD2015 安装出错
Autodesk安装失败后回滚连带把在D盘创建的安装目录都给删除掉了. 把.net 4.6卸载干净之后就可以成功安装CAD2015了.只安装.net 4.5就行了.
- 面试中的C++常见问题
1.在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”? 答:首先,extern是C/C++语言中表明函数和全局变量作用范围的关键字,该关键字告诉编译器,其声明的函数和变量可 ...
- window7 和ubuntu 双系统时 ubuntu不能引导怎么办?
假如你的Ubuntu的 / 分区是sda9,又假如 /boot分区是 sda6,在终端下输入sudo -imount /dev/sda7 /mntmount /dev/sda6 /mnt/boot ( ...
- c语言学习笔记 for循环的结构
其实感觉for循环没有while循环那么直白好理解. for(i=0;i<n;i++) { dosth(); } i=0是i的初始值. i<n是循环进行的条件. i++是每次循环要做的事情 ...
- 打印单据,A4纸,每个单据占一个A4纸,两个单据之间不挨着
打印单据,A4纸,每个单据占一个A4纸,两个单据之间不挨着 <style type="text/css" media="print">.Noprin ...
- oracle数据库之分组查询
本章内容和大家分享的是数据当中的分组查询.分组查询复杂一点的是建立在多张表的查询的基础之上,(我们在上一节课的学习中已经给大家分享了多表查询的使用技巧,大家可以自行访问:多表查询1 多表查询2)而在 ...
- windowsPhone一些不常见控件
1.InkPresenter:可以产生手写效果的控件. http://www.cnblogs.com/randylee/archive/2010/08/10/1791222.html 2.Thumb: ...