匿名函数表达式的激活有哪几种方式?本人基础不太好,请介绍的详细专业一点
难道你不会举一反三么?前面都有了,再写一遍又不会了?
var itl = actions.GetEnumerator();
while (itl.MoveNext())
{
var foo = itl.Current;
Console.WriteLine(foo());
}
不知道什么叫"激活"?是指调用么?
匿名表达式无非就是传给委托,或者作为委托参数。那么用委托名代替函数名就可以调用。
昨天的例子:
Func<int> f = foo;
f(); //相当于 foo();
这个是我在学习c#闭包的时候看见的
贴出你看见的原话。匿名委托不存在激活一说。
闭包就是函数在创建自己的时候,将需要用的变量锁住或说记忆住。
这完全是瞎说。闭包其实很简单,我们看一个简单的例子:
int i;
Func<int> f = () =>
{
int j = i +1;
return j;
};
f();
// error Console.WriteLine(j);
我们可以看到,匿名委托中可以访问外层函数体内定义的变量i,但是反之,外部的函数体没办法访问委托里的j。这种单向的关系就叫Closure(闭包)。
这里锁住、记忆住、激活都是根本没有的事情。如同不懂科学的人才相信人的身体内有个轮子在转。
public class TCloser
{
public Func T1()
{
var n = 999;
return () =>
{
Console.WriteLine(n);
return n;
};
}
}
class Program
{
static void Main()
{
var a = new TCloser();
var b = a.T1();
Console.WriteLine(b());
}
}那这段代码是怎么回事?
能不能给我分析讲解一下
public class TCloser
{
ClosureContext context = new ClosureContext();
int anonymousMethod()
{
Console.WriteLine(context.n);
return context.n;
}
class ClosureContext
{
public int n;
}
public Func<int> T1()
{
context.n = 999;
return anonymousMethod;
}
}
class Program
{
static void Main()
{
var a = new TCloser();
var b = a.T1();
Console.WriteLine(b());
}
}
int[] data = new int[] { 1, 2, 3, 4, 5 };
List> actions = new List>();
IEnumerator e = data.GetEnumerator();
int x = 0;
while (e.MoveNext())
{
x = (int)e.Current;
actions.Add(() => x);
}
foreach (var foo in actions)
{
Console.WriteLine(foo());
}
运行结果为什么是55555
你的代码大致相当于这段代码(不用匿名函数)
其中
ClosureContext和anonymousMethod是编译器自动产生的。
但是原理是一样的。
C#对于Closure变量的处理就是创建一个对象包装起来。
至于你说的迭代器,你可以理解为是早期C#编译器的bug,现在已经修正了。
为什么是55555?还是不明白为啥是55555
一样的,按照我说的,你可以展开成如下代码
class Program
{
static ClosureContext context = new ClosureContext();
class ClosureContext
{
public int x;
}
static int anonymousMethod()
{
Console.WriteLine(context.x);
return context.x;
}
static void Main()
{
int[] data = new int[] { 1, 2, 3, 4, 5 };
List<Func<int>> actions = new List<Func<int>>();
IEnumerator e = data.GetEnumerator();
context.x = 0;
while (e.MoveNext())
{
context.x = (int)e.Current;
actions.Add(anonymousMethod);
}
foreach (var foo in actions)
{
Console.WriteLine(foo());
}
}
}
我说了,这其实是C#编译器的bug
因为在循环中,迭代器变量的生存周期应该在迭代中,因此C#编译器应该为每次迭代保留一个变量的副本
http://msdn.microsoft.com/library/hh678682(v=vs.110).aspx
这个问题在C# 5.0已经纠正。
所以你大可不必再研究为什么是555了。实在要研究,就对照我给你的模拟编译器产生的代码去看。
注意,这只是编译器的实现,和闭包没有关系。
int[] data = new int[] { 1, 2, 3, 4, 5 };
List> actions = new List>();
IEnumerator e = data.GetEnumerator();
int x = 0;
while (e.MoveNext())
{
x = (int)e.Current;
actions.Add(() => x);
}
foreach (var foo in actions)
{
Console.WriteLine(foo());
}
能不能把第二个foreach改成while的形式,让我看看