.NET中的“闭包”是什么?
什么是封闭 ? 我们有他们在.NET?
如果它们确实存在于.NET中,请提供一个代码片段(最好用C#)来解释它?
编辑:我经历了Jon Skeet的文章 ,了解什么是闭包,以及如何在.NET中使用它们。
我有一个关于这个话题的文章 。 (它有很多例子。)
实质上,闭包是一段代码,可以在以后执行,但是它保留了它最初创build的环境,即它仍然可以使用创build它的方法的局部variables等,即使在这之后方法已经完成执行。
闭包的一般特性是在C#中通过匿名方法和lambdaexpression式实现的。
这是一个使用匿名方法的例子:
using System; class Test { static void Main() { Action action = CreateAction(); action(); action(); } static Action CreateAction() { int counter = 0; return delegate { // Yes, it could be done in one statement; // but it is clearer like this. counter++; Console.WriteLine("counter={0}", counter); }; } }
输出:
counter=1 counter=2
这里我们可以看到,由CreateAction返回的操作仍然可以访问计数器variables,并且确实可以增加它,即使CreateAction本身已经完成。
如果您有兴趣了解C#如何实现Closure,请阅读“我知道答案(它的42)博客”
编译器在后台生成一个类来封装这个匿名方法和variablesj
[CompilerGenerated] private sealed class <>c__DisplayClass2 { public <>c__DisplayClass2(); public void <fillFunc>b__0() { Console.Write("{0} ", this.j); } public int j; }
function:
static void fillFunc(int count) { for (int i = 0; i < count; i++) { int j = i; funcArr[i] = delegate() { Console.Write("{0} ", j); }; } }
把它变成:
private static void fillFunc(int count) { for (int i = 0; i < count; i++) { Program.<>c__DisplayClass1 class1 = new Program.<>c__DisplayClass1(); class1.j = i; Program.funcArr[i] = new Func(class1.<fillFunc>b__0); } }
闭包是一些function值,它们保留了原始范围内的variables值。 C#可以以匿名代表的forms使用它们。
对于一个非常简单的例子,采取这个C#代码:
delegate int testDel(); static void Main(string[] args) { int foo = 4; testDel myClosure = delegate() { return foo; }; int bar = myClosure(); }
最后,bar会被设置为4,myClosure委托可以被传递到程序中的其他地方。
闭包可用于许多有用的事情,如延迟执行或简化接口 – LINQ主要是使用闭包构build的。 对于大多数开发人员来说,最直接的方法是将事件处理程序添加到dynamic创build的控件中 – 当控件被实例化时,可以使用闭包来添加行为,而不是在别处存储数据。
Func<int, int> GetMultiplier(int a) { return delegate(int b) { return a * b; } } //... var fn2 = GetMultiplier(2); var fn3 = GetMultiplier(3); Console.WriteLine(fn2(2)); //outputs 4 Console.WriteLine(fn2(3)); //outputs 6 Console.WriteLine(fn3(2)); //outputs 6 Console.WriteLine(fn3(3)); //outputs 9
闭包是在创build函数之外传递的匿名函数。 它维护它所使用的创build函数的所有variables。
下面是我从JavaScript中的类似代码创build的C#的一个人为的例子:
public delegate T Iterator<T>() where T : class; public Iterator<T> CreateIterator<T>(IList<T> x) where T : class { var i = 0; return delegate { return (i < x.Count) ? x[i++] : null; }; }
所以,这里是一些代码,显示如何使用上面的代码…
var iterator = CreateIterator(new string[3] { "Foo", "Bar", "Baz"}); // So, although CreateIterator() has been called and returned, the variable // "i" within CreateIterator() will live on because of a closure created // within that method, so that every time the anonymous delegate returned // from it is called (by calling iterator()) it's value will increment. string currentString; currentString = iterator(); // currentString is now "Foo" currentString = iterator(); // currentString is now "Bar" currentString = iterator(); // currentString is now "Baz" currentString = iterator(); // currentString is now null
希望这有些帮助。
基本上,闭包是可以作为parameter passing给函数的一段代码。 C#支持以匿名代表的forms进行闭包。
这是一个简单的例子:
List.Find方法可以接受并执行一段代码(闭包)来查找列表项。
// Passing a block of code as a function argument List<int> ints = new List<int> {1, 2, 3}; ints.Find(delegate(int value) { return value == 1; });
使用C#3.0语法,我们可以这样写:
ints.Find(value => value == 1);
闭包是大量的代码,在它们之外引用一个variables(从栈底下面),这个variables可能会在以后被调用或执行(比如当一个事件或者委托被定义,并且可能在某个不确定的未来时间点被调用)…由于代码块的外部variables可能超出了范围(否则将会丢失),因此被大块代码(称为闭包)引用的事实告诉运行时间“保持“这个variables的范围,直到它不再需要封闭的代码块…
闭包是函数在另一个函数(或方法)内部定义的,它使用了父方法的variables。 位于方法中的variables的使用和封装在其中的函数被称为闭包。
Mark Seemann在他的博客文章中提供了一些closures的例子,他在oop和函数式编程之间做了一个并列。
并使其更详细
var workingDirectory = new DirectoryInfo(Environment.CurrentDirectory);//when this variable Func<int, string> read = id => { var path = Path.Combine(workingDirectory.FullName, id + ".txt");//is used inside this function return File.ReadAllText(path); };//the entire process is called a closure.
我一直在试图理解它,下面是Javascript和C#中的相同代码的代码片断,显示闭包。
- 计数每个事件发生次数或每个button被点击的次数。
JavaScript:
var c = function () { var d = 0; function inner() { d++; alert(d); } return inner; }; var a = c(); var b = c(); <body> <input type=button value=call onClick="a()"/> <input type=button value=call onClick="b()"/> </body>
C#:
using System.IO; using System; class Program { static void Main() { var a = new a(); var b = new a(); a.call(); a.call(); a.call(); b.call(); b.call(); b.call(); } } public class a { int b = 0; public void call() { b++; Console.WriteLine(b); } }
- 计数点击事件发生总次数或者不pipe控制点击总数。
JavaScript的:
var c = function () { var d = 0; function inner() { d++; alert(d); } return inner; }; var a = c(); <input type=button value=call onClick="a()"/> <input type=button value=call onClick="a()"/>
C#:
using System.IO; using System; class Program { static void Main() { var a = new a(); var b = new a(); a.call(); a.call(); a.call(); b.call(); b.call(); b.call(); } } public class a { static int b = 0; public void call() { b++; Console.WriteLine(b); } }
闭包是一个在函数中定义的函数,它可以访问它的局部variables以及它的父项。
public string GetByName(string name) { List<things> theThings = new List<things>(); return theThings.Find<things>(t => t.Name == name)[0]; }
所以find方法里面的函数。
t => t.Name == name
可以访问其范围内的variablest和父范围内的variables名。 即使它是由find方法作为委托来执行,从另一个作用域一起执行。