About闭包
using System;
using System.Collections.Generic;
using System.Collections;
class Program
{
static void Main(string[] args)
{
//第一个例子
//int counter = 0;
//IEnumerable<int> values = Utilities.Generate(10, () => counter++);
//Console.WriteLine("Current Counter: {0}", counter);
//foreach (int num in values)
// Console.WriteLine(num);
//Console.WriteLine("Current Counter: {0}", counter);
//foreach (int num in values)
//{
// Console.WriteLine(num);
//}
//Console.WriteLine("Current Counter: {0}", counter);
//IEnumerator<int> obj = GetEnumerator();
//foreach (var item in obj)
//{
// Console.WriteLine(item);
//}
//第二个例子
A a=new A();
IEnumerable<int> arr = a.Fun();
foreach (var tem in arr)
{
Console.WriteLine(tem);
}
foreach (var tem in arr)
{
Console.WriteLine(tem);
}
//第三个例子
//foreach (var item in a)
//{
// Console.WriteLine(item);
//}
//Console.WriteLine("-------------------------------");
//foreach (var item in a)
//{
// Console.WriteLine(item);
//}
}
}
class A : IEnumerable<int>
{
int count = 0;
public IEnumerator<int> GetEnumerator()
{
for (int i = 0; i < 5; i++)
yield return count++;
}
IEnumerator IEnumerable.GetEnumerator()
{
for (int i = 0; i < 5; i++)
yield return count++;
}
public IEnumerable<int> Fun()
{
for (int i = 0; i < 5; i++)
yield return count++;
}
}
class B : IEnumerable<int>
{
#region IEnumerable<int> 成员
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
#region IEnumerable 成员
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
public static class Utilities
{
public static IEnumerable<T> Generate<T>(int num, Func<T> generator)
{
int index = 0;
while (index++ < num)
yield return generator();
}
}
闭包的实现原理:
在.NET 1.x时我们可能会写这样的代码:1
public static void TestRequest(string url)
{
WebRequest request = HttpWebRequest.Create(url);
object[] context = new object[] { url, request };
request.BeginGetResponse(TestAsyncCallback, context);
}
public static void TestAsyncCallback(IAsyncResult ar)
{
object[] context = (object[])ar.AsyncState;
string url = (string)context[0];
WebRequest request = (WebRequest)context[1];
using (WebResponse response = request.EndGetResponse(ar))
{
Console.WriteLine("{0}: {1}", url, response.ContentLength);
}
}我们需要自己维护一个object[]作为callback的参数,这样不仅是弱类型还很麻烦。好在.NET 2.x引入了匿名方法:
public static void TestRequest(string url)
{
WebRequest request = HttpWebRequest.Create(url);
request.BeginGetResponse(delegate(IAsyncResult ar)
{
using (WebResponse response = request.EndGetResponse(ar))
{
Console.WriteLine("{0}: {1}", url, response.ContentLength);
}
},
null);
}很方便吧!2 新定义的delegate可以直接用TestRequest里的变量,就在于生成了一个闭包。
闭包(Closure)是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。3
C#中闭包的实现
从上边看来闭包与匿名方法有点关系,但.NET中本并没有什么匿名方法,我们还是用Reflector看下编译器到底生成了什么样的代码。这里注意要修改下Reflector的设置,View->Options->Disassembler->Optimization改为.Net 1.0 。
public static void TestRequest(string url)
{
<>c__DisplayClass1 CS$<>8__locals2 = new <>c__DisplayClass1();
CS$<>8__locals2.url = url;
CS$<>8__locals2.request = WebRequest.Create(CS$<>8__locals2.url);
CS$<>8__locals2.request.BeginGetResponse(new AsyncCallback(CS$<>8__locals2.<TestRequest>b__0), null);
}
[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Fields
public WebRequest request;
public string url;
// Methods
public void b__0(IAsyncResult ar)
{
using (WebResponse response = this.request.EndGetResponse(ar))
{
Console.WriteLine("{0}: {1}", this.url, response.ContentLength);
}
}
}
可见编译器至少做了两件事
生成了一个类,包括匿名方法的方法体和所有引用的自由变量
调用匿名方法的方法里的相关变量都被替换为生成类的字段,相关方法被替换为生成类的方法