闭包中变量捕获的详细说明

我见过无数关于变量捕获如何引入变量以创建闭包的文章,但是它们似乎都缺乏具体细节,并称其为“编译器魔术”。

我正在寻找以下方面的明确解释:

  1. 如何 实际 捕获局部变量。
  2. 捕获值类型与引用类型之间的差异(如果有)。
  3. 以及是否有关于值类型的装箱发生。

我更倾向于根据值和指针(更接近内部发生的事情)回答问题,尽管我也会接受涉及值和引用的明确答案。

回答:

  1. 是棘手的。一分钟内就会出现。
  2. 没什么区别-在两种情况下,捕获的都是变量本身。
  3. 不,没有拳击发生。

通过示例演示捕获的工作方式可能是最简单的…

这是一些使用lambda表达式捕获单个变量的代码:

using System;

class Test

{

static void Main()

{

Action action = CreateShowAndIncrementAction();

action();

action();

}

static Action CreateShowAndIncrementAction()

{

Random rng = new Random();

int counter = rng.Next(10);

Console.WriteLine("Initial value for counter: {0}", counter);

return () =>

{

Console.WriteLine(counter);

counter++;

};

}

}

现在,这就是编译器为您执行的操作-只是它将使用“无法说”的名称,而这在C#中是不可能真正出现的。

using System;

class Test

{

static void Main()

{

Action action = CreateShowAndIncrementAction();

action();

action();

}

static Action CreateShowAndIncrementAction()

{

ActionHelper helper = new ActionHelper();

Random rng = new Random();

helper.counter = rng.Next(10);

Console.WriteLine("Initial value for counter: {0}", helper.counter);

// Converts method group to a delegate, whose target will be a

// reference to the instance of ActionHelper

return helper.DoAction;

}

class ActionHelper

{

// Just for simplicity, make it public. I don't know if the

// C# compiler really does.

public int counter;

public void DoAction()

{

Console.WriteLine(counter);

counter++;

}

}

}

如果捕获在循环中声明的变量,那么ActionHelper对于循环的每次迭代,您都会得到一个新的实例-这样您就可以有效地捕获变量的不同“实例”。

当您捕获来自不同作用域的变量时,它会变得更加复杂…让我知道您是否真的想要那种详细程度,或者您可以编写一些代码,在Reflector中反编译然后按照以下步骤进行:)

注意如何:

  • 没有拳击
  • 没有涉及指针或任何其他不安全的代码

编辑:这是两个代表共享变量的示例。一个代表显示的当前值counter,另一个代表增加它的值:

using System;

class Program

{

static void Main(string[] args)

{

var tuple = CreateShowAndIncrementActions();

var show = tuple.Item1;

var increment = tuple.Item2;

show(); // Prints 0

show(); // Still prints 0

increment();

show(); // Now prints 1

}

static Tuple<Action, Action> CreateShowAndIncrementActions()

{

int counter = 0;

Action show = () => { Console.WriteLine(counter); };

Action increment = () => { counter++; };

return Tuple.Create(show, increment);

}

}

…以及扩展:

using System;

class Program

{

static void Main(string[] args)

{

var tuple = CreateShowAndIncrementActions();

var show = tuple.Item1;

var increment = tuple.Item2;

show(); // Prints 0

show(); // Still prints 0

increment();

show(); // Now prints 1

}

static Tuple<Action, Action> CreateShowAndIncrementActions()

{

ActionHelper helper = new ActionHelper();

helper.counter = 0;

Action show = helper.Show;

Action increment = helper.Increment;

return Tuple.Create(show, increment);

}

class ActionHelper

{

public int counter;

public void Show()

{

Console.WriteLine(counter);

}

public void Increment()

{

counter++;

}

}

}

以上是 闭包中变量捕获的详细说明 的全部内容, 来源链接: utcz.com/qa/398318.html

回到顶部