具有 IDisposable 的无限状态机

2024-01-19

假设我有一个无限状态机来生成随机 md5 哈希值:

public static IEnumerable<string> GetHashes()
{
    using (var hash = System.Security.Cryptography.MD5.Create())
    {
        while (true)
            yield return hash.ComputeHash(Guid.NewGuid().ToByteArray());
    }
}

在上面的例子中我使用了using陈述。会不会.Dispose()方法曾经被调用过吗? CQ,非托管资源会被释放吗?

例如,如果我按如下方式使用机器:

public static void Test()
{
    int counter = 0;
    var hashes = GetHashes();
    foreach(var md5 in hashes)
    {
        Console.WriteLine(md5);
        counter++;
        if (counter > 10)
            break;
    }
}

自从hashes变量将超出范围(并且我假设垃圾收集)是否会调用 dispose 方法来释放所使用的资源System.Security.Cryptography.MD5或者这是内存泄漏?


让我们稍微更改一下原始代码块,将其归结为要点,同时仍然保持其足够有趣以进行分析。这并不完全等同于您发布的内容,但我们仍在使用迭代器的值。

class Disposable : IDisposable {
    public void Dispose() {
        Console.WriteLine("Disposed!");
    }
}

IEnumerable<int> CreateEnumerable() {
    int i = 0;
    using (var d = new Disposable()) {
       while (true) yield return ++i;
    }
}

void UseEnumerable() {
    foreach (int i in CreateEnumerable()) {
        Console.WriteLine(i);
        if (i == 10) break;
    }
}

这将在打印之前打印从 1 到 10 的数字Disposed!

幕后到底发生了什么?还有很多。我们先处理外层,UseEnumerable. The foreach是以下内容的语法糖:

var e = CreateEnumerable().GetEnumerator();
try {
    while (e.MoveNext()) {
        int i = e.Current;
        Console.WriteLine(i);
        if (i == 10) break;
    }
} finally {
    e.Dispose();
}

对于确切的细节(因为即使这也被简化了一点)我建议你C# 语言规范 https://www.microsoft.com/download/details.aspx?id=7029,第 8.8.4 节。这里重要的一点是foreach需要隐式调用Dispose的枚举器。

接下来,using中的声明CreateEnumerable也是语法糖。事实上,让我们用原始语句写出整个内容,以便稍后我们可以更理解翻译:

IEnumerable<int> CreateEnumerable() {
    int i = 0;
    Disposable d = new Disposable();
    try {
       repeat: 
       i = i + 1;
       yield return i;
       goto repeat;
    } finally {
       d.Dispose();
    }
}

语言规范第 10.14 节详细介绍了迭代器块实现的确切规则。它们以抽象操作而非代码的形式给出。关于 C# 编译器生成什么类型​​的代码以及每个部分的作用的很好的讨论在C# 深入探讨 http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx,但我将提供一个仍然符合规范的简单翻译。重申一下,这不是编译器会做的actually产生,但它是一个足够好的近似值来说明正在发生的事情,并且忽略了处理线程和优化的更多毛茸茸的部分。

class CreateEnumerable_Enumerator : IEnumerator<int> {
    // local variables are promoted to instance fields
    private int i;
    private Disposable d;

    // implementation of Current
    private int current;
    public int Current => current;
    object IEnumerator.Current => current;

    // State machine
    enum State { Before, Running, Suspended, After };
    private State state = State.Before;

    // Section 10.14.4.1
    public bool MoveNext() {
        switch (state) {
            case State.Before: {
                    state = State.Running;
                    // begin iterator block
                    i = 0;
                    d = new Disposable();
                    i = i + 1;
                    // yield return occurs here
                    current = i;
                    state = State.Suspended;
                    return true;
                }
            case State.Running: return false; // can't happen
            case State.Suspended: {
                    state = State.Running;
                    // goto repeat
                    i = i + 1;
                    // yield return occurs here
                    current = i;
                    state = State.Suspended;
                    return true;
                }
            case State.After: return false; 
            default: return false;  // can't happen
        }
    }

    // Section 10.14.4.3
    public void Dispose() {
        switch (state) {
            case State.Before: state = State.After; break;
            case State.Running: break; // unspecified
            case State.Suspended: {
                    state = State.Running;
                    // finally occurs here
                    d.Dispose();
                    state = State.After;
                }
                break;
            case State.After: return;
            default: return;    // can't happen
        }
    }

    public void Reset() { throw new NotImplementedException(); }
}

class CreateEnumerable_Enumerable : IEnumerable<int> {
  public IEnumerator<int> GetEnumerator() {
    return new CreateEnumerable_Enumerator();
  }

  IEnumerator IEnumerable.GetEnumerator() {
    return GetEnumerator();
  }
}

IEnumerable<int> CreateEnumerable() {
  return new CreateEnumerable_Enumerable();
}

这里的要点是代码块在出现时被分割yield return or yield break语句,迭代器负责记住中断时“我们在哪里”。任何finally体内的块被推迟到Dispose。代码中的无限循环实际上不再是无限循环,因为它被周期性中断yield return声明。注意,because the finally块实际上不是finally不再阻塞,当你处理迭代器时,它的执行就不太确定了。这就是为什么使用foreach(或任何其他确保Dispose迭代器的方法在 a 中被调用finally块)是必不可少的。

这是一个简化的例子;当你使循环变得更加复杂、引入异常等等时,事情会变得更加有趣。 “只是让这个工作”的负担落在编译器身上。

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

具有 IDisposable 的无限状态机 的相关文章

  • C++ 维护子类对象的混合集合

    如果我在这里错过了一个相当基本的概念 我很抱歉 但我正在尝试弄清楚如何维护多个类类型的集合 所有类类型都派生自同一个父类 并且在检索它们时仍然可以访问它们的特定于子类的方法从集合中 作为上下文 我有一个基类 BaseClass 和许多类 例
  • 为什么在连接两个字符串时 Python 比 C 更快?

    目前我想比较 Python 和 C 用来处理字符串的速度 我认为 C 应该比 Python 提供更好的性能 然而 我得到了完全相反的结果 这是 C 程序 include
  • CLR 2.0 与 4.0 性能比较?

    如果在 CLR 4 0 下运行 为 CLR 2 0 编译的 NET 程序会运行得更快吗 应用程序配置
  • C++ 是否可以在 MacOS 上与 OpenMP 和 boost 兼容?

    我现在已经尝试了很多事情并得出了一些结论 也许 我监督了一些事情 但似乎我无法完成我想要的事情 问题是 是否有可能使用 OpenMP 和 boost 在 MacOS High Sierra 上编译 C 一些发现 如果我错了请纠正我 Open
  • IdentityServer 4 对它的工作原理感到困惑

    我阅读和观看了很多有关 Identity Server 4 的内容 但我仍然对它有点困惑 因为似乎有很多移动部件 我现在明白这是一个单独的项目 它处理用户身份验证 我仍然不明白的是用户如何注册它 谁存储用户名 密码 我打算进行此设置 Rea
  • 如何在C(Linux)中的while循环中准确地睡眠?

    在 C 代码 Linux 操作系统 中 我需要在 while 循环内准确地休眠 比如说 10000 微秒 1000 次 我尝试过usleep nanosleep select pselect和其他一些方法 但没有成功 一旦大约 50 次 它
  • 对 std::vector 进行排序但忽略某个数字

    我有一个std vector
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • 类型约束

    我有以下类层次结构 class Header IEnumerable
  • 识别 Visual Studio 中的重载运算符 (c++)

    有没有办法使用 Visual Studio 快速直观地识别 C 中的重载运算符 在我看来 C 中的一大问题是不知道您正在使用的运算符是否已重载 Visual Studio 或某些第三方工具中是否有某些功能可以自动突出显示重载运算符或对重载运
  • 使用valgrind进行GDB远程调试

    如果我使用远程调试gdb我连接到gdbserver using target remote host 2345 如果我使用 valgrind 和 gdb 调试内存错误 以中断无效内存访问 我会使用 target remote vgdb 启动
  • 检测到严重错误 c0000374 - C++ dll 将已分配内存的指针返回到 C#

    我有一个 c dll 它为我的主 c 应用程序提供一些功能 在这里 我尝试读取一个文件 将其加载到内存 然后返回一些信息 例如加载数据的指针和内存块的计数到 c Dll 成功将文件读取到内存 但在返回主应用程序时 程序由于堆损坏而崩溃 检测
  • Unity:通过拦截将两个接口注册为一个单例

    我有一个实现两个接口的类 我想对该类的方法应用拦截 我正在遵循中的建议Unity 将两个接口注册为一个单例 https stackoverflow com questions 1394650 unity register two inter
  • C++ new * char 不为空

    我有一个问题 我在 ASIO 中开发服务器 数据包采用尖头字符 当我创建新字符时 例如char buffer new char 128 我必须手动将其清理为空 By for int i 0 i lt 128 i buffer i 0x00
  • String.Empty 与 "" [重复]

    这个问题在这里已经有答案了 可能的重复 String Empty 和 有什么区别 https stackoverflow com questions 151472 what is the difference between string
  • 可访问性不一致:参数类型的可访问性低于方法

    我试图在两个表单之间传递一个对象 基本上是对当前登录用户的引用 目前 我在登录表单中有一些类似的内容 private ACTInterface oActInterface public void button1 Click object s
  • 为boost python编译的.so找不到模块

    我正在尝试将 C 代码包装到 python 中 只需一个类即可导出两个函数 我编译为map so 当我尝试时import map得到像噪音一样的错误 Traceback most recent call last File
  • Objective-C / C 给出枚举默认值

    我在某处读到过关于给枚举默认值的内容 如下所示 typedef enum MarketNavigationTypeNone 0 MarketNavigationTypeHeirachy 1 MarketNavigationTypeMarke
  • 是否可以在不连接数据库的情况下检索 MetadataWorkspace?

    我正在编写一个需要遍历实体框架的测试库MetadataWorkspace对于给定的DbContext类型 但是 由于这是一个测试库 我宁愿不连接到数据库 它引入了测试环境中可能无法使用的依赖项 当我尝试获取参考时MetadataWorksp
  • 不区分大小写的字符串比较 C++ [重复]

    这个问题在这里已经有答案了 我知道有一些方法可以进行忽略大小写的比较 其中涉及遍历字符串或一个good one https stackoverflow com questions 11635 case insensitive string

随机推荐

  • 如何在 Razor 页面中获取 ASP.NET 身份验证票证过期?

    我将 Identityserver4 与 ASP NET Identity 结合使用 并使用配置为 SlidingExpiration true 和 ExpireTimeSpan 20 分钟的 cookie 我想在用户即将超时时向他们提供警
  • IIS Express 7.5 wwwroot 目录在哪里

    使用 Windows 7 我已经安装了 IIS Express 7 5 但我找不到wwwroot我系统上的目录 没有 inetpub我的 C 盘上也有 文件夹 您能否让我知道在哪里可以放置要运行的文件 例如 hello aspx 文件 Th
  • 如何检索当前为微调器设置的阵列适配器?安卓操作系统、机器人

    希望创建一个菜单切换器 在旋转器的两个可能的数组之间切换 例如 如果微调器设置为显示数组 A 那么当我按下此菜单按钮时 我希望将微调器设置为数组 B 如果我再次按下它 我希望将其设置回数组 A 我可以处理 if then 语句等 但如何调用
  • 子网格缓存或阻止子网格数据被删除 (jqGrid)

    有没有办法强制 jqGrid 在切换行时不删除子网格数据 我当前加载数据网格的过程如下 1 设置主网格 使用稍后可以使用的 ID 以编程方式设置子网格 2 通过json将数据本地加载到主网格中 3 通过json将数据添加到本地子网格 由于当
  • Wicket 和 CSS 资源

    我环顾四周 找不到将我自己的 CSS 添加到 Wicket 网站项目的傻瓜指南 但在开始之前 我对正确的 java 开发还很陌生 所以当我说 傻瓜指南 时 我是认真的 非常感谢这里对我简单明了的解释 我从这里开始阅读本指南 http wic
  • Spring Integration - 变压器和标头丰富器

    我的情况是这样的 我需要根据邮政编码将消息路由到三个不同的商店 为此 我需要查看邮件标头以查找客户的邮政编码 并执行以下计算 if zip lt 5000 store SJ else if zip gt 6000 store JY else
  • 为什么 Clojure 的多方法比“if”或“case”语句更好

    我花了一些时间试图理解 Clojure 多方法 据我了解 主要的 专业 多方法论点是它们的灵活性 但是 我对为什么多方法比简单的 if 或 case 语句更好的争论感到困惑 请有人解释一下 多态性和过度美化的案例陈述之间的界限在哪里 编辑
  • 了解 Cassandra 的存储开销

    我一直在阅读本节 http www datastax com documentation cassandra 2 0 cassandra architecture architecturePlanningUserData t html查阅
  • 如何以编程方式设置layout_margin? [复制]

    这个问题在这里已经有答案了 我想知道如何使用屏幕高度和宽度以编程方式设置layout marginLeft layout marginTop layout marginBottom 请帮我 谢谢 莫纳利 这是一个例子 改编自这个答案 htt
  • iOS 应用程序在 iOS 12 上编译器生成的代码中崩溃

    我最近发布了一个用 Swift 4 2 编写的 iOS 应用程序的新版本 Crashlytics 报告该应用程序在编译生成的代码中崩溃了 30 多次 我查看了项目中的类 并尝试重现崩溃 但未成功 有谁有办法解决编译器生成的代码中发生的崩溃吗
  • ASP .NET Core 2.0 将“localhost”更改为“主机名”

    我有一个基于MVC框架编写的Web应用程序 它在本地主机和默认端口 51290 上运行得非常好 现在我需要使用我的域名运行它 例如我的主机名 我尝试的是在 applicationhost config 部分添加一行
  • 从后台返回时 AVCaptureSession 失败

    我有一个相机预览窗口 90 的时间都运行良好 然而 有时 当返回我的应用程序时 如果它位于后台 预览将不会显示 这是我在视图加载时调用的代码 void startCamera session AVCaptureSession alloc i
  • SearchView getActionView 返回 null

    前几天还可以用 但是突然就停止了 我只想在某些片段可见时使用操作栏搜索小部件 现在我无法获得SearchView now getActionView总是返回 null 可搜索 xml
  • 使用 php 和 mysql 发送提醒电子邮件而不使用 cron-job?

    我刚刚制作了一个 php 脚本 它将在约会开始前 2 天向网站管理员发送电子邮件提醒 我本来打算自动化脚本来运行 cron 作业 却发现我托管的人 疯狂的域 似乎没有 Cron 作业 有没有办法在没有 cron jobs 的情况下做到这一点
  • 转置没有聚合的行和列

    我有以下数据集 Account Contact 1 324324324 1 674323234 2 833343432 2 433243443 3 787655455 4 754327545 4 455435435 5 543544355
  • 如何在此 Builder 实现中摆脱 instanceof

    The idea 我需要创建命令 命令可以配置参数 并非每个命令都可以接收相同的参数 所以有些必须被忽略 我有一个抽象类 Command 其中定义了一个 Builder 默认情况下 每个附加参数都会抛出 UnsupportedOperati
  • 在 pandas 中使用带有元组列的查询

    我有一个 pandas df 其中一列作为元组 我想用query使用元组的第一个条目对 df 进行子集化 最好的方法是什么 我在 pandas 23 3 Python 3 6 6 MWE import pandas as pd df pd
  • Gitlab-ci.yml 创建合并请求

    我在 DEV 分支中运行以下 gitlab ci yml 文件 目标也为 DEV 由于我无法将 TARGET 指向 MASTER 因此不会自动创建 MR 我想知道是否可以在 gitlab ci 脚本本身中创建合并请求 dev stage d
  • 拉力赛中的速度图[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在开展一个项目 从拉力赛中提取数据并创建速度图表 我了解要使用的 REST Web 服务 API 是缺陷 迭代 分层需求和迭代累积
  • 具有 IDisposable 的无限状态机

    假设我有一个无限状态机来生成随机 md5 哈希值 public static IEnumerable