一起谈.NET技术,C#基础之委托异步

  大家知道委托就相当于C++里面的函数指针,相信大家都很很了解,看看如下简单代码来回想一下委托


public delegate void Ad();
xu xus = new xu();
Ad b = new Ad(xus.Add);
b += xus.ex;
b();
Console.ReadLine();


class xu
{
public void Add()
{
//Thread.Sleep(5000);
Console.WriteLine("sssssssssssssssssssss");
}
public void ex()
{
//Thread.Sleep(5000);
Console.WriteLine("aaaaaaaaaaaaaaaaaaaaa");
}
}

  这里我们看见 定义了一个ADD 的委托没有参数没有返回值 然后把委托指向ADD 和ex 两个方法(多播委托) 然后执行b()  执行之后 结果大家应该知道 就是执行了这2个方法打印出 "ssssssssssssss"于"aaaaaaaaaaaaaaaa"。那如果变成下面这个形式呢?


public delegate int Ad(int x,int y);
static void Main(string[] args)
{
xu xus = new xu();
Ad a = new Ad(Add);
a += (int x, int y) => { return x - y; };
Console.WriteLine(a(3,2));
Console.ReadLine();
}
static int Add(int x, int y)
{
//Thread.Sleep(2000);
return x + y;
}
static int ex(int x, int y)
{
//Thread.Sleep(5000);
return x - y;
}
}

  这段代码 也是执行一个多播委托 但是输出的结果会是什么样的呢 答案是 输出1,为什么前面那个委托会输出2个方法 而这个委托只会输出第二个方法的返回值?如果我们也想输出2个返回值怎么办呢?其实很简单 代码如下


public delegate int Ad(int x,int y);
static void Main(string[] args)
{
xu xus = new xu();
Ad a = new Ad(Add);
a += (int x, int y) => { return x - y; };
Delegate[] d = a.GetInvocationList();
for (int i = 0; i < d.Length; i++)
{
if (d[i] is Ad)
{
Ad s = (Ad)d[i];
Console.WriteLine(s(3, 2));
}
}
Console.ReadLine();
}
static int Add(int x, int y)
{
// Thread.Sleep(2000);
return x + y;
}
static int ex(int x, int y)
{
//Thread.Sleep(5000);
return x - y;
}
}

  这里我们使用了一个GetInvocationList 方法来返回多播委托的调用列表 然后转化ad 然后循环调用 最后显示的结果就是5,1。委托的 复习我们就看到这里 现在回到正题 看看委托的异步调用。


public delegate int Ad(int x,int y);
static void Main(string[] args)
{
xu xus = new xu();
Ad a = new Ad(Add);
Console.WriteLine(a(3, 3));
Console.WriteLine("start");
Console.ReadLine();
}
static int Add(int x, int y)
{
Thread.Sleep(2000);
return x + y;
}

  运行这段代码 会先停顿2秒钟之后再显示6 和start 因为我使用了sleep这个方法 它使该线程休眠2秒钟,所以会在2秒之后显示信息,但是这对用户体验来说是非常糟糕的,那我们怎么改善呢?看看如下代码


public delegate int Ad(int x,int y);
static void Main(string[] args)
{
xu xus = new xu();
Ad a = new Ad(Add);
Console.WriteLine(a(3, 3));
// Console.WriteLine("start");
IAsyncResult isa= a.BeginInvoke(3, 3, null, null);
while (!isa.IsCompleted)
{
Console.WriteLine("未完成");
}
int s= a.EndInvoke(isa);
Console.WriteLine(s.ToString());
Console.ReadLine();
}
static int Add(int x, int y)
{
Thread.Sleep(2000);
return x + y;
}
static int ex(int x, int y)
{
//Thread.Sleep(5000);
return x - y;
}

  这里我们使用了begininvoke方法来异步执行 委托方法返回一个IAsyncResult 类型的值 代表委托执行的状态,使用一个while循环 来判断IsCompleted 如果没有完成异步调用则不断显示“未完成” 如果完成endinvoke 则返回结果。但是这里需要不断的询问操作完成状态 那么我们怎样让委托异步调用完成之后主动通知我们呢? 看看如下代码


public delegate int Ad(int x,int y);
static void Main(string[] args)
{
xu xus = new xu();
Ad a = new Ad(Add);
Console.WriteLine(a(3, 3));
IAsyncResult isa= a.BeginInvoke(3, 3, new AsyncCallback(call), "edit by xyl");
//执行你想执行的代码 这里我们还是用IsCompleted来代替
while (!isa.IsCompleted)
{
Console.WriteLine("未完成");
}
Console.ReadLine();
}
static void call(IAsyncResult isa)
{
AsyncResult ar = (AsyncResult)isa;
Ad a = (Ad)ar.AsyncDelegate;
Console.WriteLine("this is {0},{1}",a.EndInvoke(isa),ar.AsyncState);
}

static int Add(int x, int y)
{
Thread.Sleep(2000);
return x + y;
}
static int ex(int x, int y)
{
//Thread.Sleep(5000);
return x - y;
}
}

  这里我们使用了一个call方法 注意它是没有返回值的。把IAsyncResult转换成AsyncResult注意少了个I然后转换成AD 类型的委托 最后endinvoke 来返回值 这样在委托异步执行完成之后会自动通知方法。呵呵 好了今天就说到这里吧。如果有说的不对的地方欢迎指正 大家一起学习一起进步。

时间: 2024-09-12 17:04:01

一起谈.NET技术,C#基础之委托异步的相关文章

C#基础之委托异步

大家知道委托就相当于C++里面的函数指针,相信大家都很很了解,看看如下简单代码来回想一下委托 public delegate void Ad(); xu xus = new xu(); Ad b = new Ad(xus.Add); b += xus.ex; b(); Console.ReadLine(); class xu { public void Add() { //Thread.Sleep(5000); Console.WriteLine("sssssssssssssssssssss&q

一起谈.NET技术,.NET中的异步编程(二)- 传统的异步编程

在上一篇文章中,我们从构建响应灵敏的界面以及构建高可伸缩性的服务应用来讨论我们为什么需要异步编程,异步编程能给我们带来哪些好处.那么知道了好处,我们就开始吧,但是在异步编程这个方面,说总是比做简单.套用那句不是名言的名言:编写异步程序是困难的,编写可靠的异步程序尤其困难.因为异步程序非常难以编写,而且非常容易出错,很多基本的构造元素在异步编程中都无法使用,这让我们这些开发人员更愿意编写同步的代码,虽然我们知道有些地方真的应该使用异步. 如何实现异步 对于很多人来说,异步就是使用后台线程运行耗时的

一起谈.NET技术,.NET中的异步编程-Continuation passing style以及使用yield实现异步

传统的异步方式将本来紧凑的代码都分成两部分,不仅仅降低了代码的可读性,还让一些基本的程序构造无法使用,所以大部分开发人员在遇到应该使用异步的地方都忍痛割爱.本来我在本篇文章中想讨论一下.NET世界中已有的几个辅助异步开发的类库,但是经过思考后觉得在这之前介绍一下一些理论知识也许对理解后面的类库以及更新的内容有所帮助.今天我们要讨论的是Continuation Passing Style,简称CPS. CPS 首先,我们看看下面这个方法: 1: public int Add(int a, int

一起谈.NET技术,.NET中的异步编程(一)-为什么需要异步

在2010年的PDC上,微软发布了Visual Studio Async CTP,大大地降低了异步编程的难度,让我们可以像写同步的方法那样去编写异步代码.Async CTP也在社区里掀起了不小的波澜.在这之后,我也学习了一段时间,这个系列会将这段时间的学习作个梳理. 好了,下面进入本文的正题. 为什么需要异步编程 既然同步的写法更自然简单,异步的代码(传统的)不好写,还容易出错,那我们为什么需要去编写异步的代码呢?微软还要费这么大劲投入对Async CTP的开发呢?这其中肯定有一些原因. 快速响

.NET简谈互操作(五:基础知识之Dynamic平台调用)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之Dispose非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习.在上篇文章中我们学习了关于托管与非托管内存Dispose(释放)问题:下面我们继续学习基础知识中的Dyn

一步一步教你加密解密技术——前言&基础知识(1)

第1章 前言&基础知识很 多人都想学学做cracker,好象破了一个程序很风光的,人人都很佩服. 可是做一个cracker 其实很累,需花费 大量的时间,而且经常会碰壁,三五天 毫无进展是极为平常的事情.做cracker的五个必要条件是: 1. 知识 2. 经验 3. 感觉 4. 耐心 5. 运气 .如果你刚开始学crack,也许你遇到不少麻烦,并且有点想退却,其实 你不要着急,只要你认真学习,成功就在眼前.没有人是生来就什么都会的,如果你有问题,就大胆的去问你周围的人,多来我主页论坛请教.计算

.NET简谈互操作(六:基础知识之提升平台调用性能)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之Dispose非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习.本篇文章我们将来学习互操作基础知识中的最后一个知识点"提升平台调用的性能": 在于非托管函数进

.NET简谈互操作(三:基础知识之DllImport特性)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之释放非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用) .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习,上一篇文章中我们介绍了托管代码怎么与非托管代码C++之间的互操作:要想在托管代码中成功的进行非托管调用,要注意的细

.NET简谈互操作(四:基础知识之Dispose非托管内存)

互操作系列文章: .NET简谈互操作(一:开篇介绍) .NET简谈互操作(二:先睹为快) .NET简谈互操作(三:基础知识之DllImport特性) .NET简谈互操作(四:基础知识之Dispose非托管内存) .NET简谈互操作(五:基础知识之Dynamic平台调用)  .NET简谈互操作(六:基础知识之提升平台调用性能) .NET简谈互操作(七:数据封送之介绍) 我们继续.NET互操作学习.前一篇文章中我们学习了基础知识中的DllImport关键特性:我们继续学习基础知识中的内存释放相关技术