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

复制代码 代码如下:
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. C# .Net 使用zxing.dll生成二维码,条形码

    public static string GetBarcode(string format, string value, int? width, int? height)        {       ...

  2. Ubuntu 创建启动器

    首先我们要了解,Ubuntu 的 Dash 里所有程序都是在 /usr/share/applications 中的,所以我们的思路很简单——建一个类似于“快捷方式”一样的东西扔进去就好了.所以第一步自 ...

  3. C语言面试题汇总

    1.   阅读下面程序并写出输出结果(10分). main() { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); printf("%d, ...

  4. 以helloworld为例讲解magento中控制器的工作

    1.下面介绍的前提是你已经安装了magento ,版本是1.9.1.0. 2.下面是实际步骤 ①在工程下面创建下面的文件目录 app/code/local/Magentotutorial/Hellow ...

  5. Redis 集成Spring(spring-data-redis)

    Spring-data-redis是spring大家族的一部分,提供了在srping应用中通过简单的配置访问redis服务,对reids底层开发包(Jedis,  JRedis, and RJC)进行 ...

  6. mysql 数据库 简单存储过程游标使用

    BEGIN #Routine body goes here... DECLARE no_more_record INT DEFAULT 0; DECLARE TEST_ID INT(20); DECL ...

  7. vmare虚拟化解决方案

    最近刚入职一家公司!主要是做vmare虚拟化的,虽然跟openstack不太沾边,但现在很多openstack都会兼容vmare程序,最终会如何我拭目以待,今天写这个也是做一个总结. 虚拟化.云计算. ...

  8. Kattis - Biased Standings

    Biased Standings Usually, results of competitions are based on the scores of participants. However, ...

  9. centos6 安装python2.7+和神器pip

    centos自带python版本是2.6.6,需要采用编译安装的方法安装py27 1.提前yum安装python以及pip神器依赖包(有没有必要都装上就是了,早晚有用): yum install -y ...

  10. Redis客户端API操作 Jedis详解

    redis是一个著名的key-value存储系统,也是nosql中的最常见的一种.其实,个人认为,redis最强大的地方不在于其存储,而在于其强大的缓存作用. 我们可以把它想象成一个巨大的(多借点集群 ...