ZetCode

C# 闭包

最后修改于 2023 年 7 月 5 日

C# 闭包教程定义了闭包并展示了如何使用它们。

注意: 闭包的定义在其他编程语言中可能略有不同。

闭包是一个匿名委托,它可以维护对代码块定义之外的自由变量的访问。即使在方法执行完毕后,它仍然可以引用这些变量。

var limit = 0;
Predicate<int> greaterThan = e => e > limit;

我们有一个匿名 lambda 表达式,它引用了 limit 变量,即使该变量未在代码块中声明或作为参数传递。

C# 闭包示例

以下是一个简单的闭包示例。

Program.cs
var c = CreateCounter();

Console.WriteLine(c());
Console.WriteLine(c());
Console.WriteLine(c());
Console.WriteLine(c());
Console.WriteLine(c());

Func<int> CreateCounter()
{
    int c = 0;
    return () => c = c + 1;
}

CreateCounter 被调用多次;每次调用后,状态(c 的值)都会被保留。

$ dotnet run
1
2
3
4
5

C# 闭包示例 II

闭包经常用于 LINQ 代码中。

Program.cs
var vals = new int[] {-1, -2, 0, 1, 5, 3};

var limit = 0;
Func<int, bool> greaterThan = e => e > limit;

var res = vals.Where(greaterThan);

foreach (var e in res)
{
    Console.WriteLine(e);
}

在该示例中,我们定义了一个过滤器委托。在谓词中使用的 limit 变量是一个在谓词定义之外定义的自由变量。

$ dotnet run 
1
3
5 

C# 闭包示例 III

我们在迭代器示例中使用一个闭包。

Program.cs
var words = new List<string> { "sky", "cloud", "rock", "war", "web" };
var it = CreateIterator(words);

string e;

while ((e = it()) != null)
{
    Console.WriteLine(e);
}

Iterator<T> CreateIterator<T>(IList<T> data) where T : class
{
    var i = 0;
    return delegate { return (i < data.Count) ? data[i++] : null; };
}

public delegate T Iterator<T>() where T : class;

我们有一个泛型迭代器。为了使迭代器工作,我们必须保留增量变量的状态。

来源

.NET 中的闭包是什么?

在本文中,我们使用了 C# 中的闭包。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。 迄今为止,我撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程