奇怪的局部变量

微创社(MCC) 2009-08-21 01:40:51
加精
奇怪的局部变量:讨论一下C#中的闭包

[0]静态全局字段
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
class Program
{
public static int copy;//[0]这个不是闭包
static void Main()
{
//定义动作组
List<Action> actions = new List<Action>();
for (int counter = 0; counter < 10; counter++)
{
copy = counter;
actions.Add(() => Console.WriteLine(copy));
}
//执行动作
foreach (Action action in actions) action();
}
}
}

//注:Action定义如下:
//public delegate void Action();


[1]局部变量(闭包一)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
class Program
{
static void Main()
{
int copy;//[1]闭包一
//定义动作组
List<Action> actions = new List<Action>();
for (int counter = 0; counter < 10; counter++)
{
copy = counter;
actions.Add(() => Console.WriteLine(copy));
}
//执行动作
foreach (Action action in actions) action();
}
}
}

//注:Action定义如下:
//public delegate void Action();


[2]局部变量(闭包二)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
class Program
{
static void Main()
{
//定义动作组
List<Action> actions = new List<Action>();
for (int counter = 0; counter < 10; counter++)
{
int copy;//[1]闭包二
copy = counter;
//int copy = counter;//换种写法
actions.Add(() => Console.WriteLine(copy));
}
//执行动作
foreach (Action action in actions) action();
}
}
}

//注:Action定义如下:
//public delegate void Action();


[3]局部变量(闭包三)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
class Program
{
static void Main()
{
//定义动作组
List<Action> actions = new List<Action>();
for (int counter = 0; counter < 10; counter++)//[3]闭包三
{
actions.Add(() => Console.WriteLine(counter));
}
//执行动作
foreach (Action action in actions) action();
}
}
}

//注:Action定义如下:
//public delegate void Action();


[0]:输出什么?
[1]:输出什么?
[2]:输出什么?
[3]:输出什么?
...全文
1298 52 打赏 收藏 转发到动态 举报
写回复
用AI写文章
52 条回复
切换为时间正序
请发表友善的回复…
发表回复
微创社(MCC) 2009-10-06
  • 打赏
  • 举报
回复
@葛藤

见:
http://www.cnblogs.com/rndlife/archive/2008/10/20/1315354.html
闭包的副作用 段落
liyoubaidu 2009-08-25
  • 打赏
  • 举报
回复
up
getian 2009-08-25
  • 打赏
  • 举报
回复
请楼主讲一下闭包的副作用好吗?
zhw626033518 2009-08-25
  • 打赏
  • 举报
回复
这段代码代表了什么意思?他又有什么作用?
qq904492758 2009-08-24
  • 打赏
  • 举报
回复
得认真学习了!
小范f-li.cn 2009-08-24
  • 打赏
  • 举报
回复
...
lsd123 2009-08-24
  • 打赏
  • 举报
回复
.
jy251 2009-08-24
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 pcnetman888 的回复:]
CSDN你能为我带来什么:~~

是昨晚的这个贴子,引发了今天的贴子:
http://topic.csdn.net/u/20090820/15/1581a09d-9d3d-4ff3-93a9-d7d711d08cde.html

初学者有时候的想法是可笑的,
但他们会带来最最"纯粹"的想法.

我们往往会浮在C#的表面,
更多的追求一些复杂框架及模式带来的快感,
放弃的更多的"纯真"的思考.

CSDN在高度上,也许比不上一些更加"专业"的社区
但是无数的C#初学者,为我们带来了:
大量思考单纯的素材.

不要去问他们,为什么问题如此的怪异,
无论是多们的不合理,不要去改变他的想法,
去实他...
当你发现这种实现是多么的不合理时...
你应该考虑一下...
我们是不是忽视了些什么...

[/Quote]

这也是我为什么还在逛CSDN的原因。
RexZheng 2009-08-24
  • 打赏
  • 举报
回复
再举例一个解决方案:

        static void Main(string[] args)
{
List<Action> actions = new List<Action>();
Action<int> assign = (i) => actions.Add(() => Console.WriteLine(i));
for (int counter = 0; counter < 10; counter++)
{
assign(counter);
}
foreach (Action action in actions) action();
}
RexZheng 2009-08-24
  • 打赏
  • 举报
回复
这个问题根源在于滞后执行。

如楼主的闭包三:
            for (int counter = 0; counter < 10; counter++)//[3]闭包三
{
actions.Add(() => Console.WriteLine(counter));
}

当后面输出调用的时候,delegate才去执行方法体内的内容,这时候counter已经是10了,这种问题很常见啊,如果不注意的话很容易出错。

对于此类问题,强烈推荐使用楼主在第二个例子中的解决方案。
微创社(MCC) 2009-08-24
  • 打赏
  • 举报
回复
典型的闭包:
object o;
lock (o)
{
//to do
}


也许我们天天在用,只是没觉得而己。

闭包也有不少的副作用,倒是值得注意的。


lllsui 2009-08-24
  • 打赏
  • 举报
回复
up
灵雨飘零 2009-08-24
  • 打赏
  • 举报
回复
[Quote=引用 38 楼 chuyiqian 的回复:]
好长
[/Quote]
endy71985 2009-08-24
  • 打赏
  • 举报
回复
赶快找下闭包是什么 ^_^
enihs 2009-08-24
  • 打赏
  • 举报
回复
看得少也很正常,毕竟都是用c#混饭吃,不是研究c#,鉴于楼主的推荐,现在我开始闭包-〉lamda表达式-〉函数式编成->haskell语言的了解过程中。
chuyiqian 2009-08-24
  • 打赏
  • 举报
回复
好长
mqy2000 2009-08-24
  • 打赏
  • 举报
回复
ding
加油馒头 2009-08-24
  • 打赏
  • 举报
回复


昨天跟几个朋友闲谈时,提到C++的函数指针与C#的方法对象,其中讨论了一个在学习C#中很少提到的概念"闭包"

闭包

闭包是将一些执行封装,将它像对象一样传递,在传递时,执行依然能够访问到原上下文。

访问原来上下文,是闭包的重要特征

例:

由于只声明了一个i变量
所以所有的Action捕获的都是同一个i变量。结果就是每一行都输出数字10
static void Main(string[] args)
{
List<Action> ls = new List<Action>();

for (int i = 0; i < 10; i++)
{

ls.Add(() => Console.WriteLine(i));
}


foreach (Action action in ls)
{
action();
}


System.Console.Read();
}


附件: 抱歉,您所在的用户组没有浏览该资源的权限。点此升级为VIP会员自由下载全站资源!
以下方式实现了输出0到9

与上例代码的唯一不是是在循环体中使用了一个局部变量tp,这种写法在通常看来不通是多用了一个中转变量,对程的执行不会有什么影响,但事实上tp这个变量在被每个Action独立保存.

这样,每次循环体在执行的时候,都会取得一个全新的tp,而且tp不会因为所在声名体的完成而出栈
static void Main(string[] args)
{
List<Action> ls = new List<Action>();

for (int i = 0; i < 10; i++)
{
int tp = i;
ls.Add(() => Console.WriteLine(tp));
}


foreach (Action action in ls)
{
action();
}


System.Console.Read();
}

附件: 抱歉,您所在的用户组没有浏览该资源的权限。点此升级为VIP会员自由下载全站资源!


若匿名方法中的变量:
若匿名方法中如果引用了某个变量,则该局部变量将被提升为实例变量,并储存于一个叫做闭包(closure)的对象中。
提升之后,即使创建该变量的方法执行完毕该变量仍不会消亡。
当指向该匿名函数的所有引用都消失后,该闭包变量即可正常地被垃圾回收器回收

说明
class Program
{
delegate int wxd(int i);
delegate wxd lzm(int ii);

static void Main(string[] args)
{
lzm obj = delegate(int ii)
{
return
delegate(int i)
{
return i + ii;
};
};
wxd w1 = obj(1);
wxd w2 = obj(2);

System.Console.WriteLine(w1(3));
System.Console.WriteLine(w2(3));

System.Console.Read();
}
}

附件: 抱歉,您所在的用户组没有浏览该资源的权限。点此升级为VIP会员自由下载全站资源!
输出的结果是4和5
[obj]函数接受一个参数,返回新的函数[w1,w2]。新的函数[w1,w2]将[obj]的参数与自己的参数相加,返回结果

函数[w1,w2]在接受相同的参数的时候,产生了不同的结果。

实际上[obj]返回的内部函数已经把[obj]的参数[ii]记录了

在这里,方法已不仅仅是一个函数指针了

[obj]的参数[ii]是如何记录的:

通常理解,函数的参数是放在栈中的。
如果闭包也将参数放在栈中,那么[ii]在[obj]运行结束的时候就会消失掉,这个时候[w1,w2]再通过栈去搜索[ii]显然就是不可能的。
所以闭包中参数或内部变量不能放在栈中.而是放在程序执行过程之中的一张全局表里.
[[obj]在返回内部函数的时候,将全局表,自己的结构表,内部函数的指针一起传递给变量[w1,w2].
这时内部函数可以访问[ii],外部却无法访问[ii]
liffe 2009-08-23
  • 打赏
  • 举报
回复
得认真学习了!
hangang7403 2009-08-23
  • 打赏
  • 举报
回复
学习
做了一下测试
【0】9 9 9 9 9 9 9 9 9 9
【1】9 9 9 9 9 9 9 9 9 9
【2】0 1 2 3 4 5 6 7 8 9
【3】10 10 10 10 10 10 10 10 10 10
加载更多回复(31)

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧