ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C#的"闭包"

2021-04-09 12:05:55  阅读:173  来源: 互联网

标签:闭包 f1 f2 sub C# int add 函数


最近在学习golang的时候发现一件有趣的事情,go有一个闭包的概念,于是我对比了一下C#的"闭包"...

  • golang的闭包

calc 是一个接收一个形参a、两个函数返回值的函数,两个函数返回值是指这一段代码:(func(int) int, func(int) int),go语言支持多个返回值
main 函数,所有语言一样程序的入口
【1】 通过main函数调用calc函数执行返回两个函数,分别是f1和f2,同时会打印一边参数a的内存地址
【2】 调用f1函数和f2函数,打印一遍add和sub里面"引用"calc函数参数a的内存地址,并返回calc参数a+=i和a-=i的结果
【3】 输出f1函数和f2函数执行返回的结果 

 1 func calc(a int) (func(int) int, func(int) int) {
 2     //打印变量地址
 3     fmt.Println(&a)
 4 
 5     //创建a+=add函数入参i,并返回的a的结果的函数,并返回给调用者
 6     add := func(i int) int {
 7         //返回值函数内部打印一遍变量地址,测试这里面的a和calc的a内存地址是否一致
 8         fmt.Println(&a)
 9         a += i
10         return a
11     }
12     //创建a-=sub函数入参i,并返回的a的结果的函数,并返回给调用者
13     sub := func(i int) int {
14         fmt.Println(&a)
15         a -= i
16         return a
17     }
18     //返回两个函数
19     return add, sub
20 }
21 
22 func main() {
23     //f1对应add f2对应sub
24     f1, f2 := calc(10)
25     //调用f1和f2函数,同时打印f1 f2返回结果
26     fmt.Println(f1(1), f2(2)) //11 9
27     fmt.Println(f1(3), f2(4)) //12 8
28     fmt.Println(f1(5), f2(6)) //13 7
29 }

 打印结果:

0xc00000a0a8      调用calc函数所打印 fmt.Println(&a) 的结果

0xc00000a0a8      调用f1(1) add里面的 fmt.Println(&a) 
0xc00000a0a8      调用f2(2) sub里面的 fmt.Println(&a) 
11 9           f1(1)和f2(2) 返回值

0xc00000a0a8      调用f1(3) 
0xc00000a0a8      调用f1(4) 
12 8           f1(3)和f2(4) 返回值

0xc00000a0a8      调用f1(5) 
0xc00000a0a8      调用f1(6) 
13 7           f1(5)和f2(6) 返回值

是不是很惊讶,calc函数参数a这个值变量变成了引用关系,在calc函数执行完之后并没有释放,并供给add和sub使用,这就是go的闭包。

 

  • C#的"闭包"

 通过下面代码能“实现”上面golang的闭包

 1 public void Calc(int a, out Func<int, int> add, out Func<int, int> sub)
 2 {
 3     add = (int i) =>
 4     {
 5         return a += i;
 6     };
 7 
 8     sub = (int i) =>
 9     {
10         return a -= i;
11     };
12 }
13 
14 public void Show()
15 {
16     Func<int, int> f1;
17     Func<int, int> f2;
18     this.Calc(10, out f1, out f2);
19 
20     Console.WriteLine(string.Format("{0}  {1}", f1(1), f2(2)));
21     Console.WriteLine(string.Format("{0}  {1}", f1(3), f2(4)));
22     Console.WriteLine(string.Format("{0}  {1}", f1(5), f2(6)));
23 }

 返回值打印结果:

11 9
12 8
13 7

得出结论确实是能实现和golang上面代码一样的功能,calc函数参数a变量变成"引用"关系,提供给add和sub使用。

但是...我将代码改了下

 1 public class TestFunc
 2 {
 3     //存储内存地址的字典,供后续查看
 4     private unsafe Dictionary<string, int*[]> PADic = new Dictionary<string, int*[]>();
 5 
 6     public void Calc(int a, out Func<int, int> add, out Func<int, int> sub)
 7     {
 8         //运行执行不安全的代码
 9         unsafe
10         {
11             //取a的内存地址
12             int* aa = (int*)a;
13             //将内存地址存储到字典中
14             this.PADic.Add("Calc(a):", new int*[] { aa });
15         }
16 
17         add = (int i) =>
18         {
19             unsafe
20             {
21                 int* aa = (int*)a;
22                 this.PADic.Add(string.Format("f1({0}):", i), new int*[] { aa });
23             }
24             return a += i;
25         };
26 
27         sub = (int i) =>
28         {
29             unsafe
30             {
31                 int* aa = (int*)a;
32                 this.PADic.Add(string.Format("f2({0}):", i), new int*[] { aa });
33             }
34             return a -= i;
35         };
36     }
37 
38     public void Show()
39     {
40         Func<int, int> f1;
41         Func<int, int> f2;
42         this.Calc(10, out f1, out f2);
43         Console.WriteLine(string.Format("{0}  {1}", f1(1), f2(2))); // 11 9
44         Console.WriteLine(string.Format("{0}  {1}", f1(3), f2(4))); // 12 8
45         Console.WriteLine(string.Format("{0}  {1}", f1(5), f2(6))); // 13 7
46     }
47 }

 (指针地址没办法输出,直接调试看变量内容)输出结果:

 

通过上面代码可以看出,每次调用f1和f2的时候,所"引用"的参数a是“值复制”的,而不是引用,因为它们的内存地址是有变化。

得出结论,功能虽然都能实现,但是有本质区别的。

 

标签:闭包,f1,f2,sub,C#,int,add,函数
来源: https://www.cnblogs.com/gsheng/p/14635078.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有