关于C#委托三种调用的分享使用

一、同步调用

1、同步调用会按照代码顺序来执行
2、同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕的用户体验,这时候异步调用就很有必要了。

举个栗子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;

namespace Test
{
  public delegate int AddHandler(int a, int b);
  public class Calc
  {
    public static int Add(int a, int b)
    {
      Console.WriteLine("开始计算:" + a + "+" + b);
      Thread.Sleep(3000); //模拟该方法运行三秒
      Console.WriteLine("计算完成!");
      return a + b;
    }
  }
  class Program
  {
    static void Main(string[] args)
    {
       Console.WriteLine("===== 同步调用 SyncInvokeTest =====");
      AddHandler handler = new AddHandler(Calc.Add);
      int result = handler.Invoke(1, 2);
      Console.WriteLine("继续做别的事情。。。");
      Console.WriteLine(result);
      Console.ReadKey();
    }
  }
}

* 问:为什么Invoke的参数和返回值和AddHandler委托是一样的呢?
* 答:Invoke方法的参数很简单,一个委托,一个参数表(可选),
而Invoke方法的主要功能就是帮助你在UI线程上调用委托所指定的方法。
Invoke方法首先检查发出调用的线程(即当前线程)是不是UI线程,
如果是,直接执行委托指向的方法,如果不是,它将切换到UI线程,
然后执行委托指向的方法。不管当前线程是不是UI线程,
Invoke都阻塞直到委托指向的方法执行完毕,然后切换回发出调用的
线程(如果需要的话),返回。
所以Invoke方法的参数和返回值和调用他的委托应该是一致的。

二、异步调用

1、异步调用不阻塞线程,而是把调用塞到线程池中,
2、程序主线程或UI线程可以继续执行。
3、委托的异步调用通过BeginInvoke和EndInvoke来实现。

举个栗子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;

namespace Test
{
  public delegate int AddHandler(int a, int b);
  public class Calc
  {
    public static int Add(int a, int b)
    {
      Console.WriteLine("开始计算:" + a + "+" + b);
      Thread.Sleep(3000); //模拟该方法运行三秒
      Console.WriteLine("计算完成!");
      return a + b;
    }
  }
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("===== 异步调用 AsyncInvokeTest =====");
      AddHandler handler1 = new AddHandler(Calc.Add);
      //IAsyncResult: 异步操作接口(interface)
      //BeginInvoke: 委托(delegate)的一个异步方法的开始
      IAsyncResult result1 = handler1.BeginInvoke(1, 2, null, null);

      Console.WriteLine("继续做别的事情1。。。");
      //异步操作返回
      Console.WriteLine(handler1.EndInvoke(result1));//会等待加法类计算,如果没计算好就堵塞线程
      Console.WriteLine("继续做别的事情2。。。");
      Console.ReadKey();
    }
  }
}

注意:
* BeginInvoke : 开始一个异步的请求,调用线程池中一个线程来执行,
* 返回IAsyncResult 对象(异步的核心). IAsyncResult 简单的说,
* 它存储异步操作的状态信息的一个接口,也可以用他来结束当前异步。
* 注意: BeginInvoke和EndInvoke必须成对调用.即使不需要返回值,
* 但EndInvoke还是必须调用,否则可能会造成内存泄漏。

结果:

可以看到,主线程并没有等待,而是直接向下运行了。
但是问题依然存在,当主线程运行到EndInvoke时,如果这时调用没有结束(这种情况很可能出现),这时为了等待调用结果,线程依旧会被阻塞。

三、异步回调

用回调函数,当调用结束时会自动调用回调函数,解决了为等待调用结果,而让线程依旧被阻塞的局面。

举个栗子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;

namespace Test
{
  public delegate int AddHandler(int a, int b);
  public class Calc
  {
    public static int Add(int a, int b)
    {
      Console.WriteLine("开始计算:" + a + "+" + b);
      Thread.Sleep(3000); //模拟该方法运行三秒
      Console.WriteLine("计算完成!");
      return a + b;
    }
  }
  class Program
  {
    static void Main(string[] args)
    {
     Console.WriteLine("===== 异步回调 AsyncInvokeTest =====");
      AddHandler handler2 = new AddHandler(Calc.Add);
      //异步操作接口(注意BeginInvoke方法的不同!)
      IAsyncResult result2 = handler2.BeginInvoke(1, 2, new AsyncCallback(MyCallBack),
        "AsycState:OK");
      Console.WriteLine("继续做别的事情。。。");
      Console.ReadKey();
    }
    static void MyCallBack(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,

result 是“加法calc.Add()方法”的返回值

AsyncResult 是IAsyncResult接口的一个实现类,空间:System.Runtime.Remoting.Messaging

必须将异步委托强制转换为 AddHandler。可以在异步回调函数(类型为 AsyncCallback)中调用 AddHandler.EndInvoke,以获取最初提交的 AddHandler.BeginInvoke 的结果。

ok,三种委托调用的分享就到这里了

到此这篇关于关于C#委托三种调用的分享使用的文章就介绍到这了,更多相关C#委托调用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C#异步委托调用实例分析

    本文实例讲述了C#异步委托调用实现方法.分享给大家供大家参考.具体如下: static void Main(string[] args) { //委托异步 Action<string> showMessage = ShowMessage; IAsyncResult result = showMessage.BeginInvoke("测试异步委托",null, null); //那在异步线程未完成工作以前主线程将处于阻塞状态 //等到异步线程结束,主线程才能继续工作 show

  • C#通过委托调用Button单击事件的方法

    这里介绍通过委托取消Button事件switch-case的方法.需要注意的是,事先要按顺序在各个Button的Tag属性中设置0.1.2.3--等序号,其作用请详看代码. /*定义委托*/ public delegate 类型或viod MethodDelegate(参数1, 参数2); private void buttonC_Click(object sender, EventArgs e) { Button button = (Button)sender; /*向委托添加方法*/ Met

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

    首先,通过代码定义一个委托和下面三个示例将要调用的方法: 复制代码 代码如下: public delegate int AddHandler(int a,int b);    public class 加法类    {        public static int Add(int a, int b)        {            Console.WriteLine("开始计算:" + a + "+" + b);            Thread.Sl

  • C#使用委托的形式调用线程代码实例

    委托 对于委托,我们都知道他是一个引用类型,具有引用类型所具有的通性.需要知道的是它保存的不是实际值,只是是保存对存储在托管堆中的对象的引用.或说的直接点,委托就相当于叫人帮忙,让你帮你做一些事情.我这里就使用委托的形式,调用线程,来简单的说一下. 代码如下: using System; using System.Threading; namespace _012_线程 { class Program { static void Main(string[] args) //在mian中线程是执行

  • 解析C#中委托的同步调用与异步调用(实例详解)

    委托的Invoke方法用来进行同步调用.同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行.同步调用的例子: 复制代码 代码如下: using System;using System.Threading;public delegate int AddHandler(int a, int b);public class Foo { static void Main() {  Console.WriteLine("**********SyncInvokeTest***

  • 关于C#委托三种调用的分享使用

    一.同步调用 1.同步调用会按照代码顺序来执行 2.同步调用会阻塞线程,如果是要调用一项繁重的工作(如大量IO操作),可能会让程序停顿很长时间,造成糟糕的用户体验,这时候异步调用就很有必要了. 举个栗子: using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threadi

  • Python列表删除的三种方法代码分享

    1.使用del语句删除元素 >>> i1 = ["a",'b','c','d'] >>> del i1[0] >>> print(i1) ['b', 'c', 'd'] >>> del语句将值从列表中删除后,就再也无法访问它了. 2.使用pop()删除元素 pop()可删除列表末尾的元素,并让你能够接着使用它.食欲弹出(pop)源自这样的类比:列表就是一个栈,而删除列表末尾的元素相当于弹出栈顶元素. >>

  • 详解java 三种调用机制(同步、回调、异步)

    1:同步调用:一种阻塞式调用,调用方要等待对方执行完毕才返回,它是一种单向调用 2:回调:一种双向调用模式,也就是说,被调用方在接口被调用时也会调用对方的接口: 3:异步调用:一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口 具体说来:就是A类中调用B类中的某个方法C,然后B类中反过来调用A类中的方法D,D这个方法就叫回调方法, 实例1:使用java中Timer来在给定时间间隔发送通知,每隔十秒打印一次数据 Tim

  • Java 字符终端上获取输入三种的方式分享

    在Java 字符终端上获取输入有三种方式: 1.java.lang.System.in (目前JDK版本均支持)2.java.util.Scanner (JDK版本>=1.5)3.java.io.Console(JDK版本>=1.6),特色:能不回显密码字符 参考:这里记录Java中从控制台读入信息的几种方式(1)JDK 1.4(JDK 1.5和JDK 1.6也都兼容这种方法) 复制代码 代码如下: public class TestConsole1 {      public static

  • js三种排序算法分享

    复制代码 代码如下: /** * 值交换操作 * arr 被操作的数组 * i 被操作元素索引值 * j 被操作两元素的距离 */ function refer(arr, i, j){ var change = (arr[i] - arr[i - j]) < 0 ? true : false, value; if (change) { value = arr[i]; arr[i] = arr[i - j]; arr[i - j] = value; return arguments.callee(

  • C# 三种序列化方法分享

    序列化是将一个对象转换成字节流以达到将其长期保存在内存.数据库或文件中的处理过程.它的主要目的是保存对象的状态以便以后需要的时候使用.与其相反的过程叫做反序列化. 序列化一个对象为了序列化一个对象,我们需要一个被序列化的对象,一个容纳被序列化了的对象的(字节)流和一个格式化器.进行序列化之前我们先看看System.Runtime.Serialization名字空间.ISerializable接口允许我们使任何类成为可序列化的类. 如果我们给自己写的类标识[Serializable]特性,我们就能

  • PHP中数组的三种排序方法分享

    一.冒泡排序法 说明:找到最大的数,排列到最后面,然后继续找 例: 复制代码 代码如下: $arr = array(3,5,-1,0,2); for($i=0;$i<count($arr)-1;$i++){ for($j=0;$j<count($arr)-1-$i;$j++){ if($arr[$j]>$arr[$j+1]){ $temp = $arr[$j]; $arr[$j]=$arr[$j+1]; $arr[$j+1]=$temp; } } } 理解: 3,5,-1,0,2 //从

  • vue中三种调用接口的方法

    目录 1. this.$api.LeadershipScreen.getImportantRiskList(params) 2.需要引用 3.axios(需要先安装axios) 4.配置request 1. this.$api.LeadershipScreen.getImportantRiskList(params) 在api文件下层级关系如下图: 在index.js下 // 导入所有接口 import api from './api' const install = Vue => { if (

  • 在Shell脚本中调用另一个脚本的三种方式讲解

    先来说一下主要以下有几种方式: fork: 如果脚本有执行权限的话,path/to/foo.sh.如果没有,sh path/to/foo.sh. exec: exec path/to/foo.sh source: source path/to/foo.sh fork fork 是最普通的, 就是直接在脚本里面用 path/to/foo.sh 来调用 foo.sh 这个脚本,比如如果是 foo.sh 在当前目录下,就是 ./foo.sh.运行的时候 terminal 会新开一个子 Shell 执行

随机推荐