ImageVerifierCode 换一换
格式:DOCX , 页数:10 ,大小:19.90KB ,
资源ID:5017130      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5017130.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(解析C#与NET闭包对比示例.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

解析C#与NET闭包对比示例.docx

1、解析C#与NET闭包对比示例解析C#与.NET闭包对比示例文章分析了C#与闭包用法,C#中,闭包其实和类中其他属性、方法是一样的,它们的原则都是下一层可以畅快的调用上一层定义的各种设定,但上一层则不具备访问下一层设定的能力。 首先想说明一点,虽然有这样那样的不好的心态(比如中文技术书),但总体来说,国内的技术人员还是喜欢分享和教导别人的,这点我的个人感受和之前在园子里看到的朋友的感受恰恰相反。个人认为其实国内很多技术网友都是很热心的,可能因为语言问题同一个技术热点会稍稍落后国外一些,但有些成熟的或者基础的概念都可以找到很细致的中文介绍,特别是关于闭包,因为它的字面解释确实很绕,所以基本所有试图

2、解释这一名词的同学都是尽量用自己认为最通俗易懂的方式来进行讲解。闲话扯远了,这里我就用C#语言来给大家解释下闭包吧。其实要提到闭包,我们还得先提下变量作用域和变量的生命周期。在C#里面,变量作用域有三种,一种是属于类的,我们常称之为field,第二种则属于函数的,我们通常称之为局部变量,还有一种,其实也是属于函数的,不过它的作用范围更小,它只属于函数局部的代码片段,这种同样称之为局部变量。这三种变量的生命周期基本都可以用一句话来说明,每个变量都属于它所寄存的对象,即变量随着其寄存对象生而生和消亡。对应三种作用域我们可以这样说,类里面的变量是随着类的实例化而生,同时伴随着类对象的资源回收而消亡(

3、当然这里不包括非实例化的static和const对象)。而函数(或代码片段)的变量也随着函数(或代码片段)调用开始而生,伴随函数(或代码片段)调用结束而自动由GC释放,它内部变量生命周期满足先进后出的特性。那么这里有没有例外呢?答案是有的,不过在提这点之前,我还需要给各位另外一个名词。都说c#就是MS版本的java,这话在.net 1.0可能可以这么说,但自2.0之后C#就可以自豪的说它绝非java了,这里面委托有很大的功劳,如果用过java和C#的人并且尝试过写winform程序时全部手写实现代码的人就会有这样一个感受,同样的click事件在java中必须要无端的套个匿名类,但在c#中,你是

4、可以直接将函数名+=到事件之后而不需要显示写上匿名委托的对象类型的,因为编译器会帮你做这部分工作,在3.0和以后的版本之中,微软将委托的用法更是发挥的淋漓精致,无论是简洁的Lamda还是通俗易懂的LINQ,都是源自委托的。你可能要问,委托和我们今天要讲的闭包又有什么关系呢?我们知道,c#,java和javascript,ruby,python这些语言不同,在c#和java的世界里面,原子对象就是类(当然还有struct和基本变量),而不是很多动态语言中的函数,我们可以实例化一个类,实例化一个变量,但不可以直接new一个函数。也就是表面上看,我们是没办法像js那样将函数进行实例化和传递的。这也是

5、为什么直到Java 7闭包才被姗姗来迟的加入java特性中。但对C#来说这些只是表象,我刚学c#的时候,看到最多的解释委托的话就是:委托啊,就相当于c+里面的函数指针啦。这句话虽然笼统,但确实有一定道理,通过委托特别是匿名委托这层对象的包装,我们就可以突破无法将函数当做对象传递的限制了。好像这里还是没讲到闭包和委托的关系,好吧,我太啰嗦了,下面从概念开始讲。闭包其实就是使用的变量已经脱离其作用域,却由于和作用域存在上下文关系,从而可以在当前环境中继续使用其上文环境中所定义的一种函数对象。好拗口,程序员,还是用示例来说明更好理解。首先来个最简单的javascript中常常见到的关于闭包的例子:1

6、. public class TCloser 2. 3. 4. 5. public Func T1() 6. 7. 8. 9. var n = 999; 10. 11. return () = 12. 13. 14. 15. Console.WriteLine(n); 16. 17. return n; 18. 19. ; 20. 21. 22. 23. 24. 25. 26. 27. class Program 28. 29. static void Main() 30. 31. var a =new TCloser(); 32. 33. var b = a.T1(); 34. 35. Co

7、nsole.WriteLine(b(); 36. 37. 38. 39. 从上面的代码我们不难看到,变量n实际上是属于函数T1的局部变量,它本来生命周期应该是伴随着函数T1的调用结束而被释放掉的,但这里我们却在返回的委托b中仍然能调用它,这里正是闭包所展示出来的威力,因为T1调用返回的匿名委托的代码片段中我们用到了n,而在编译器看来,这些都是合法的,因为返回的委托b和函数T1存在上下文关系,也就是说匿名委托b是允许使用它所在的函数或者类里面的局部变量的,于是编译器通过一系列动作(具体动作我们后面再说)使b中调用的函数T1的局部变量自动闭合,从而使该局部变量满足新的作用范围。因此如果你看到.ne

8、t中的闭包,你就可以像js中那样理解它,由于返回的匿名函数对象是在函数T1中生成的,因此相当于它是属于T1的一个属性。如果你把T1的对象级别往上提升一个层次就很好理解了,这里就相当于T1是一个类,而返回的匿名对象则是T1的一个属性,对属性而言,它可以调用它所寄存的对象T1的任何其他属性或者方法,包括T1寄存的对象TCloser内部的其他属性。如果这个匿名函数会被返回给其他对象调用,那么编译器会自动将匿名函数所用到的方法T1中的局部变量的生命周转期自动提升并与匿名函数的生命周期相同,这样就称之为闭合。也许你会说,这个返回的委托包含的变量n只是编译器通过某种方式隐藏的对这个委托对象的一个同样对象的

9、赋值吧,那么我们再对比下面两个方法:1. public class TCloser 2. 3. public Func T1() 4. 5. 6. 7. var n = 999; 8. 9. Func result = () = 10. 11. 12. 13. return n; 14. 15. ; 16. 17. 18. 19. n = 10; 20. 21. return result; 22. 23. 24. 25. 26. 27. public dynamic T2() 28. 29. 30. 31. var n = 999; 32. 33. dynamic result =new A

10、 = n ; 34. 35. n = 10; 36. 37. return result; 38. 39. 40. 41. static void Main() 42. 43. var a = new TCloser(); 44. 45. var b = a.T1(); 46. 47. var c = a.T2(); 48. 49. Console.WriteLine(b(); 50. 51. Console.WriteLine(c.A); 52. 53. 54. 55. 最后输出结果是什么呢?答案是10和999,因为闭包的特性,这里匿名函数中所使用的变量就是实际T1中的变量,与之相反的是,匿

11、名对象result里面的A只是初始化时被赋予了变量n的值,它并不是n,所以后面n改变之后A并未随之而改变。这正是闭包的魔力所在。你可能会好奇.net本身并不支持函数对象,那么这样的特性又是从何而来呢?答案是编译器,我们一看IL代码便会明白了。首先我给出c#代码:1. public class TCloser 2. 3. public Func T1() 4. 5. var n = 10; 6. 7. return () = 8. 9. 10. 11. return n; 12. 13. ; 14. 15. 16. 17. 18. 19. public Func T4() 20. 21. ret

12、urn () = 22. 23. 24. 25. var n = 10; 26. 27. return n; 28. 29. ; 30. 31. 32. 33. 这两个返回的匿名函数的唯一区别就是返回的委托中变量n的作用域不一样而已,T1中变量n是属于T1的,而在T4中,n则是属于匿名函数本身的。但我们看看IL代码就会发现这里面的大不同了:1. .method public hidebysig instance class mscorlibSystem.Func1 T1() cil managed 2. 3. .maxstack 3 4. 5. .locals init ( 6. 7. 0 c

13、lass ConsoleApplication1.TCloser/c_DisplayClass1 CS$8_locals2, 8. 9. 1 class mscorlibSystem.Func1 CS$1$0000) 10. 11. L_0000: newobj instance void ConsoleApplication1.TCloser/c_DisplayClass1:.ctor() 12. 13. L_0005: stloc.0 14. 15. L_0006: nop 16. 17. L_0007: ldloc.0 18. 19. L_0008: ldc.i4.s 10 20. 21

14、. L_000a: stfld int32 ConsoleApplication1.TCloser/c_DisplayClass1:n 22. 23. L_000f: ldloc.0 24. 25. L_0010: ldftn instance int32 ConsoleApplication1.TCloser/c_DisplayClass1:b_0() 26. 27. L_0016: newobj instance void mscorlibSystem.Func1:.ctor(object, native int) 28. 29. L_001b: stloc.1 30. 31. L_001

15、c: br.s L_001e 32. 33. L_001e: ldloc.1 34. 35. L_001f: ret 36. 37. 38. 39. 40. 41. .method public hidebysig instance class mscorlibSystem.Func1 T4() cil managed 42. 43. 44. 45. .maxstack 3 46. 47. .locals init ( 48. 49. 0 class mscorlibSystem.Func1 CS$1$0000) 50. 51. L_0000: nop 52. 53. L_0001: ldsf

16、ld class mscorlibSystem.Func1 ConsoleApplication1.TCloser:CS$9_CachedAnonymousMethodDelegate4 54. 55. L_0006: brtrue.s L_001b 56. 57. L_0008: ldnull 58. 59. L_0009: ldftn int32 ConsoleApplication1.TCloser:b_3() 60. 61. L_000f: newobj instance void mscorlibSystem.Func1:.ctor(object, native int) 62. 6

17、3. L_0014: stsfld class mscorlibSystem.Func1 ConsoleApplication1.TCloser:CS$9_CachedAnonymousMethodDelegate4 64. 65. L_0019: br.s L_001b 66. 67. L_001b: ldsfld class mscorlibSystem.Func1 ConsoleApplication1.TCloser:CS$9_CachedAnonymousMethodDelegate4 68. 69. L_0020: stloc.0 70. 71. L_0021: br.s L_00

18、23 72. 73. L_0023: ldloc.0 74. 75. L_0024: ret 76. 77. 看IL代码你就会很容易发现其中究竟了,在T1中,函数对返回的匿名委托构造的是一个类,名称为newobj instance void ConsoleApplication1.TCloser/c_DisplayClass1:.ctor(),而在T4中,则是仍然是一个普通的Func委托,只不过级别变为类级别了而已。那我们接着看看T1中声明的类c_DisplayClass1是何方神圣:1. .class auto ansi sealed nested private beforefieldin

19、it c_DisplayClass1 2. 3. extends mscorlibSystem.Object 4. 5. .custom instance void mscorlibSystem.Runtime.CompilerServices.CompilerGeneratedAttribute:.ctor() 6. 7. .method public hidebysig specialname rtspecialname instance void .ctor() cil managed 8. 9. .method public hidebysig instance int32 b_0()

20、 cil managed 10. 11. .field public int32 n 12. 13. 看到这里想必你已经明白了,在C#中,原来闭包只是编译器玩的花招而已,它仍然没有脱离.NET对象生命周期的规则,它将需要修改作用域的变量直接封装到返回的类中变成类的一个属性n,从而保证了变量的生命周期不会随函数T1调用结束而结束,因为变量n在这里已经成了返回的类的一个属性了。看到这里我想大家应该大体上了解C#闭包的来龙去脉了吧,C#中,闭包其实和类中其他属性、方法是一样的,它们的原则都是下一层可以畅快的调用上一层定义的各种设定,但上一层则不具备访问下一层设定的能力。即类中方法里的变量可以自由访问类中的所有属性和方法,而闭包又可以访问它的上一层即方法中的各种设定。但类不可以访问方法的局部变量,同理,方法也不可以访问其内部定义的匿名函数所定义的局部变量。这正是C#中的闭包,它通过超越java语言的委托打下了闭包的第一步基础,随后又通过各种语法糖和编译器来实现如今在.NET世界全面开花的Lamda和LINQ。也使得我们能够编写出更加简洁优雅的代码。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1