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

复制代码 代码如下:
public delegate int AddHandler(int a,int b);
    public class 加法类
    {
        public static int Add(int a, int b)
        {
            Console.WriteLine("开始计算:" + a + "+" + b);
            Thread.Sleep(3000); //模拟该方法运行三秒
            Console.WriteLine("计算完成!");
            return a + b;
        }
    }

同步调用

委托的Invoke方法用来进行同步调用。同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行。

复制代码 代码如下:
public class 同步调用
{
        static void Main()
        {
            Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);
            int result = handler.Invoke(1, 2);
            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(1, 2, 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(1,2,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(3000); //模拟该方法运行三秒
            Console.WriteLine("计算完成!");
            return a + b;
       }
    }

public class 同步调用
    {
       static void Main()
        {
            Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
            AddHandler handler = new AddHandler(加法类.Add);
            int result = handler.Invoke(1, 2);

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(1, 2, 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(1,2,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);
        }
    }
}

C# 委托的三种调用示例(同步调用 异步调用 异步回调)的更多相关文章

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

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

  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. 关闭Windows 2008下面应用程序出错后的提示

    写了一个服务器端程序,没有能处理所有的错误,总有一些错误会抛出到系统中去.于是写了一个进程守护者,一旦发现服务器端退出,可以在第一时间重新启动服务器,也算是一种折中的方案吧.理论上讲应该是可行的,但是 ...

  2. 熬之滴水成石:Spring--精简的J2EE(7)

                                              49--持久性 关于持久性在最早的Delphi单元中,就曾介绍过.持久性是数据库中读取,保存,或删除数据的过程.毫无 ...

  3. 分享一个javascript alert精简框架

    如果你不喜欢浏览器自带的alert你可以尝试总共不超过10KB somke js  下载地址:http://smoke-js.com/ 使用方法 somke.alert("hello wor ...

  4. 用Arduino做一个可视化网络威胁级别指示器!

    在当今世界,网络监控器是非常重要的.互联网是个可怕的地方.人们已经采取措施以提高警戒----他们安装了入侵检测系统(IDS)比如SNORT. 通过把可视化部分从电脑中移出来,我们想让它更容易去观察.一 ...

  5. ColorMatrixFilter色彩矩阵滤镜(as3)

    matrix是一个长度为4*5=20的数组,其构成如下所示: R  ,G,  B,  A, offset [1,  0,  0,  0,  0]); // red [0,  1,  0,  0,  0 ...

  6. webpack中加载CSS

    webpack强大之处在于可以将CSS当做一个资源模块进行管理和加载 基本使用: 安装webpack的加载插件style-loader和css-loader: npm install style-lo ...

  7. 结构-行为-样式-Javascript笔记

    一.console.dir()可以显示一个对象所有的属性和方法. 二.递归遍历一个数据集合: A.数据: {  "menu": [    {      "menuId&q ...

  8. Node.js(初识)

    之前有了解过一点Node.js,只是一直停留在文字描述,没有真正使用过Node.js,如今因为工作的原因,开始真正接触到Node.js,也开始深入学习. Node.js具体是用来做什么的,我想一开始接 ...

  9. angularjs过滤器(一)------禁止转载------

    如果用代码实现:将new Date()转换为 M/D/YY 00:00 格式. 启用过滤器有两种方式:①在HTML中用"|"启用过滤器.格式为{{$scope.property | ...

  10. TMCache

    TMCache设计的目的是用于存储临时持久化对象的开源iOS/OS  key/value缓存类库,减少重复创建像下载数据.缓慢的处理结果这样的昂贵性能花销.TMCache由两个本身相似的存储组成,一个 ...