闭包在 for 和 foreach 循环中的行为不同

2023-11-24

在 C# 中尝试闭包时,我发现如果它们在循环中捕获迭代器变量,它们的工作效果会相当出乎意料。

var actions = new List<Action>();

foreach (int i in new[] { 1, 2 })
    actions.Add(() => Console.WriteLine(i));

for (int i = 3; i <= 4; i++)
    actions.Add(() => Console.WriteLine(i));

foreach (var action in actions)
    action();

上面的代码产生了一个奇怪的结果(我使用的是.NET 4.5编译器):

1
2
5
5

为什么价值是i对于两个几乎相同的循环捕获不同?


在 C# 5 及更高版本中,foreach循环声明一个separate i循环每次迭代的变量。因此,每个闭包都会捕获一个单独的变量,并且您会看到预期的结果。

In the for循环,你只有一个single i变量,它被所有闭包捕获,并随着循环的进行而修改 - 因此,当您调用委托时,您会看到该单个变量的最终值。

在 C# 2、3 和 4 中,foreach循环的行为也是如此,这基本上是never所需的行为,因此已在 C# 5 中修复。

您可以在以下位置达到相同的效果for如果在循环体范围内引入一个新变量,则循环:

for (int i = 3; i <= 4; i++)
{
    int copy = i;
    actions.Add(() => Console.WriteLine(copy));
}

有关更多详细信息,请阅读 Eric Lippert 的博客文章“关闭被认为有害的循环变量”-part 1, part 2.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

闭包在 for 和 foreach 循环中的行为不同 的相关文章

随机推荐

  • node.js 只输出三个点[重复]

    这个问题在这里已经有答案了 我在 Windows 计算机上安装了 node js 并打开了命令提示符 当我尝试 Hello World 示例时 我得到的唯一输出是三个点 node hello js 我做错了什么吗 node hello js
  • C# 反射:使用字符串类名实例化对象

    我的情况如下 我正在使用 Visual C 2010 Express 开发 Windows 窗体应用程序 当用户登录时 动态地构建一个菜单条 其中包含从数据库表加载的选项 在该表中 我保存 ID 选项名称和表单名称 所以 假设在我的项目中我
  • JSF 中“记住我”的 Cookie

    我有一个登录页面 我想添加 记住我 功能 这样 如果用户注销并再次打开页面 则会加载他的用户名和密码 为此 当用户登录 并选中 记住我 时 我会保存以下 cookie FacesContext facesContext FacesConte
  • 如何打印调用的函数?

    在调试 Python 脚本时 我真的很想知道整个程序的整个调用堆栈 理想的情况是 如果 python 有一个命令行标志 它会导致 Python 在调用时打印所有函数名称 我检查过man Python2 7 但没有找到此类内容 由于此脚本中的
  • ASP.NET 中有没有本地方法可以发出“成功消息”?

    假设您有一个类似 ASP NET ASP DetailsView 的东西来显示和编辑数据库中的单个记录 记录错误情况很简单 您添加验证和验证摘要 当您的更新表单验证失败时 它自然会发出噪音 它显示验证消息和 或验证摘要 不需要任何后面的代码
  • 如何在 Windows 上使用 youtube-dl 提取音频

    我想从 Windows 上使用 youtube dl 下载的视频中提取音频 我让 youtube dl 正常工作 但无法提取音频 此问题是由于未安装正确的音频代码造成的 当我尝试提取音频时 它告诉我以下内容 WARNING unable t
  • openXML电子表格文档返回用于MVC文件下载的字节数组

    我试图以 byte 的形式返回一个 openXML 电子表格文档 然后我可以使用它来允许我的 MVC 将该文件发送给用户 这是我的电子表格文档方法返回字节数组 using MemoryStream mem new MemoryStream
  • C++ 中用 :: 限定的命名空间

    如果 C 中的命名空间被限定 这意味着什么 例如 testing Test 是范围解析运算符 它始终意味着 在全局命名空间中搜索右侧的符号 例如 namespace testing int a 1 namespace foo namespa
  • 如何使用 Python 搜索和替换 XML 文件中的文本?

    如何搜索整个xml文件中的特定文本模式 然后用 Python 3 5 中的新文本模式替换该文本的每次出现 其他所有内容 格式 属性 注释等 都需要保持原始 xml 文件中的原样 我在 Windows win32 上运行 Python 3 5
  • 在 package.json 中设置 process.env var

    我正在尝试使用 package json 设置和检索节点应用程序 process env 变量 因此通过研究问题 我找到了一个通过 配置 部分设置 检索 process env 的示例 因此我添加了一个新配置部分如下图 config var
  • 获取 Jenkinsfile 失败的错误原因

    我有以下内容post故障部分 post failure mail subject u2639 env JOB NAME env BUILD NUMBER has failed body Build env BUILD URL is fail
  • 如何将“过滤器”应用到 AVCaptureVideoPreviewLayer

    我的应用程序当前正在使用 AVFoundation 从 iPhone 后置摄像头获取原始摄像头数据 并将其实时显示在 AVCaptureVideoPreviewLayer 上 我的目标是有条件地将简单的图像滤镜应用到预览图层 图像未保存 因
  • 如何使用 Android Studio 在 firebase 中检查“用户电子邮件已存在”

    我正在尝试更改我的代码 但是 它失败了 我的输出还是一样 也就是说 如果用户输入的电子邮件已经存在或不存在 验证 此电子邮件已被注册 还是出来了 为什么 有人可以我的编码有什么问题吗 这是我的方法 public boolean isChec
  • Next.js cookie 无法通过路由器中间件

    我正在尝试使用新的 Next Js 12 中间件功能创建一些路由保护 我的身份验证基于 cookie 上设置的 JWT 令牌 我之前已经使用 Next Js 上的 API 后端实现了这一点 没有出现任何问题 并且当点击 API 路由时 co
  • 如何在 CodeIgniter 的 url 中隐藏控制器名称?

    所以问题是我正在使用 htaccess 来隐藏 index php 但我仍然在 url 中获取控制器名称 如下所示 http example com name controller about我的问题是 是否可以隐藏控制器的名称 以便只显示
  • 错误:接口转换interface {}是[]interface {},而不是map[string]interface {}

    我正在构建一个项目 该项目从用户那里获取一个术语 然后执行谷歌搜索并返回 json 格式的标题列表 我正在使用 serpwow API 执行谷歌搜索并尝试解析响应 但是我收到错误消息 panic interface conversion i
  • 如何导出 DLL 中的类函数,但不是整个类

    我开发了一个 Win32 DLL 提供了下面的详细信息 并希望为函数 Connnect 和 LogOut 创建一个 CLI C 包装器 我知道可以从 DLL 导出整个类和函数 class CClientLib public CClientL
  • iOS 8 SDK:模态 UIWebView 和相机/图像选择器

    我发现 在针对 iOS 8 进行编译 并在 iOS 8 中运行 时 UIWebView无法显示相机 图像选择器 如果UIWebView位于以模态方式呈现的视图控制器中 它在直接 悬挂 在窗口上的视图控制器中工作没有问题rootViewCon
  • 猴子补丁 Python 类

    我有一个类 位于一个单独的模块中 我无法更改它 from module import MyClass class ReplaceClass object MyClass ReplaceClass 除了这个文件之外 这不会改变 MyClass
  • 闭包在 for 和 foreach 循环中的行为不同

    在 C 中尝试闭包时 我发现如果它们在循环中捕获迭代器变量 它们的工作效果会相当出乎意料 var actions new List