Duc*_*tro 57 .net c# closures value-type reference-type
我已经看到关于变量捕获如何为变量创建闭包的无数帖子,但是它们似乎都没有具体细节,并且把整个事情称为"编译魔术".
我正在寻找一个明确的解释:
我倾向于根据值和指针(更接近内部发生的核心)的答案,尽管我会接受一个涉及值和引用的明确答案.
Jon*_*eet 79
通过示例演示捕获的工作原理可能最简单......
这是使用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++;
};
}
}
Run Code Online (Sandbox Code Playgroud)
现在这就是编译器为你做的 - 除了它会使用在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++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果捕获循环中声明的变量,则最终会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);
}
}
Run Code Online (Sandbox Code Playgroud)
...和扩展:
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++;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9792 次 |
| 最近记录: |