首先,通过代码定义一个委托和下面三个示例将要调用的方法:

代码如下:

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# 委托的三种调用示例(同步调用、异步调用、异步回调)的更多相关文章

  1. C# 委托的三种调用示例(同步调用 异步调用 异步回调)

    首先,通过代码定义一个委托和下面三个示例将要调用的方法: 复制代码 代码如下: public delegate int AddHandler(int a,int b);    public class ...

  2. 20160711--C# 委托的三种调用示例(同步调用 异步调用 异步回调)【转载】

    首先,通过代码定义一个委托和下面三个示例将要调用的方法: 代码如下: public delegate int AddHandler(int a,int b); public class 加法类 { p ...

  3. php发送post请求的三种方法示例

    本文分享下php发送post请求的三种方法与示例代码,分别使用curl.file_get_content.fsocket来实现post提交数据,大家做个参考. php发送post请求的三种方法,分别使 ...

  4. unity 三种注入示例

    /* * 演示Unity 注入 * */ using Microsoft.Practices.Unity; using System; namespace Unity.Property.Inject ...

  5. css渐变写法 从左到右渐变三种颜色示例;

    background:linear-gradient(to right,#7f06a8,#a02bc2,#7f06a8)

  6. SpringBoot2.0.2 Application调用的三种方式

    一.注解 @SpringBootApplication            点开查看源码是由多个注解合成的注解,其中主要的注解有:            @SpringBootConfigurati ...

  7. C# 委托高级应用----线程——创建无阻塞的异步调用(一)

    前言 本文大部分内容来自于mikeperetz的Asynchronous Method Invocation及本人的一些个人体会所得,希望对你有所帮助.原英文文献可以在codeproject中搜索到. ...

  8. 谈.Net委托与线程——创建无阻塞的异步调用(一)

    前言 本文大部分内容来自于mikeperetz的Asynchronous Method Invocation及本人的一些个人体会所得,希望对你有所帮助.原英文文献可以在codeproject中搜索到. ...

  9. MySQL冗余数据的三种方案

    一,为什么要冗余数据 互联网数据量很大的业务场景,往往数据库需要进行水平切分来降低单库数据量. 水平切分会有一个patition key,通过patition key的查询能够直接定位到库,但是非pa ...

随机推荐

  1. Python基础学习五 内置模块

    time 模块 1 >>> import time 2 >>> time.time() 3 1491064723.808669 4 >>> # t ...

  2. Spark的几个问题

    1.application是由driver和executor组成的,executor可以分成task,task又可以分成为stage.当一个任务提交给spark之后,spark机群的主节点会出现dri ...

  3. JUNIT的用法简要总结

    JUNIT是一个单元测试框架,可以用来测试我们程序中的某个模块是否工作正常.而不需要去写一个MAIN函数来测试,方便快捷. 经过对博客http://blog.csdn.net/andycpp/arti ...

  4. 无锁的同步策略——CAS操作详解

    目录 1. 从乐观锁和悲观锁谈起 2. CAS详解 2.1 CAS指令 2.3 Java中的CAS指令 2.4 CAS结合失败重试机制进行并发控制 3. CAS操作的优势和劣势 3.1 CAS相比独占 ...

  5. 665. Non-decreasing Array只允许修改一位数的非递减数组

    [抄题]: Given an array with n integers, your task is to check if it could become non-decreasing by mod ...

  6. matplotlib的颜色和控制条

    为了方便记忆,收藏备用 一 linestyle '-' solid line style '--' dashed line style '-.' dash-dot line style ':' dot ...

  7. selenium+phantomjs解析JS

    背景知识: PhantomJS 是一个基于WebKit的服务器端 JavaScript API.它全面支持web而不需浏览器支持,其快速,原生支持各种Web标准: DOM 处理, CSS 选择器, J ...

  8. dynamic和nullable一起使用时的注意

    dynamic和nullable一起使用时的注意

  9. Redis主从服务部署

    Redis__WindowsServer主从服务部署及调用实例       一.先谈谈单个Redis服务的安装         使用的redis是2.8.17版本,从官网下载解压缩后文件内容为:   ...

  10. 团队项目第六周-Alpha阶段项目复审(深海划水队)

    经小组讨论后得出以下排名: 队名 优点 缺点 排名 大猪蹄子队 界面优美,功能简洁易懂,单词解释较为完善 互动方式.操作简易性有待优化,有部分功能尚未完成 1 Running Duck队 基本功能已经 ...