博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#异步编程之:(一)Task对象和lamda表达式探究
阅读量:5051 次
发布时间:2019-06-12

本文共 2733 字,大约阅读时间需要 9 分钟。

基于TPL的异步编程,最简单的就是使用Task对象,而创建一个Task对象,最简单的就是使用lamda表达式:

static void Main(string[] args) {            // create the cancellation token source            CancellationTokenSource tokenSource = new CancellationTokenSource();            // create the cancellation token            CancellationToken token = tokenSource.Token;            int i = 0;            int value = 10;            // create the first task, which we will let run fully            Task task1 = new Task(() => {                for (i = 0; i < Int32.MaxValue; i++)                {                    value++;                    bool cancelled = token.WaitHandle.WaitOne(10000);                    if (cancelled) {                        throw new OperationCanceledException(token);                    }                }            }, token);            // start task            task1.Start();            // cancel the token            tokenSource.Cancel();            // wait for input before exiting            Console.WriteLine("Main method complete. Press enter to finish with value = " + value.ToString());            Console.ReadLine();        }
好,在Task对象的lamda表达式里面,我们引用了外部的成员:i, value, token。那么到底.Net编译器做了什么,能让我们访问这些外部成员呢?原理很简单,这个是经过ILSpy反编译之后的源代码(把特殊的反编译选项全部disable掉):

// Listing_13.Listing_13private static void Main(string[] args){	Listing_13.<>c__DisplayClass1 <>c__DisplayClass = new Listing_13.<>c__DisplayClass1();	CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();	<>c__DisplayClass.token = cancellationTokenSource.Token;	<>c__DisplayClass.i = 0;	<>c__DisplayClass.value = 10;	Task task = new Task(new Action(<>c__DisplayClass.
b__0), <>c__DisplayClass.token); task.Start(); cancellationTokenSource.Cancel(); Console.WriteLine("Main method complete. Press enter to finish with value = " + <>c__DisplayClass.value.ToString()); Console.ReadLine();}
.Net编译器,为lamda表达式创建了一个新的类,<>c__DislayClass
(这个很奇怪,我记得await编译出来的,是生成一个Structure,难道是.Net 4.5做了优化了?),而lamda表达式本身变成了一个函数<Main>b_0, 引用的外部成员,都变车了类成员.i, .value, .token,注意这里没有多余的变量产生。注意,在整个main函数里面,这里所有被lamda引用的变量

好,我们来看看这个<>c__DisplayClass是什么东西:

[CompilerGenerated]private sealed class <>c__DisplayClass1{	public CancellationToken token;	public int i;	public int value;	public void 
b__0() { this.i = 0; while (this.i < 2147483647) { this.value++; bool flag = this.token.WaitHandle.WaitOne(10000); if (flag) { throw new OperationCanceledException(this.token); } this.i++; } }}

特性CompilerGenerated表明,这个是编译器产生的,所以类名可以使用<>前缀。这个类没什么特别,和lamda表达式一摸一样!所以,现在一切都清晰明了了!哈哈,就像侯捷所说,源码之前,了无秘密。

要注意的是,编译器把外部变量都变成了DisplayClass的成员,所以假如异步方法还没有执行前(或者没有执行完前),就改变了外部变量的值,会影响异步方法的。(相当于修改了成员变量的值)

转载于:https://www.cnblogs.com/puncha/archive/2012/12/18/3877016.html

你可能感兴趣的文章
js-创建对象的几种方式
查看>>
JDK JRE Java虚拟机的关系
查看>>
2018.11.20
查看>>
word20161215
查看>>
12th week blog
查看>>
dijkstra (模板)
查看>>
编译Linux驱动程序 遇到的问题
查看>>
大型分布式网站架构技术总结
查看>>
HDU 1017[A Mathematical Curiosity]暴力,格式
查看>>
[算法之美] KMP算法的直观理解
查看>>
EntityFramework 性能优化
查看>>
【ASP.NET开发】菜鸟时期的ADO.NET使用笔记
查看>>
android圆角View实现及不同版本号这间的兼容
查看>>
OA项目设计的能力③
查看>>
Cocos2d-x3.0 文件处理
查看>>
全面整理的C++面试题
查看>>
Activity和Fragment生命周期对比
查看>>
android 分辨率自适应
查看>>
查找 EXC_BAD_ACCESS 问题根源的方法
查看>>
日常报错
查看>>