首页 文章

引用using()块之外的对象

提问于
浏览
2

关于这个主题有很多问题,但是我没有找到一个涵盖我特别需要理解的内容 .

我的一位开发人员编写了这段代码:

//

    //  ValidationDataTable is a typed DataTable, generated by the Framework
    ValidationDataTable  validationTable;
    using (ValidationTableAdapter adapter = new ValidationTableAdapter ()) {
        using (validationTable = adapter.GetData()) { }
    }

    datafeedValidators.Add(new CountryFieldValidator(validationTable.ToDictionary(key => key.CountryCode, value => value.CountryName)));

    //  Party on...

//

我的理解:当在最后一个代码行中引用validationTable时,它已被处理但不是垃圾收集 - 但仍应在 .ToDictionary() 调用上抛出 ObjectDisposedException . 但是这段代码很乐意构建一个有效的字典并继续前进 .

我有理论,但找不到确定或击落其中任何一个的确定性 . 并且可以通过十几种方式重写代码以避免问题;那不是问题 . 我只需要知道我理解的差距是什么 .

我的问题:

  • 此代码是否有效且表现如何?

  • 如果没有,我们看到的成功是否只是一个废话?

  • 是否有一些特定的 DataTable 允许在对象被释放后进行访问 - 类似于 GZipStream 类要求你处理对象以刷新流的方式,因此允许在对象被处置后调用 .ToArray().GetBuffer()

  • ...调用方法时实际导致抛出ObjectDisposedException的原因是什么?我一直认为它来自.NET框架本身 .

.

CLARIFICATION:

这是一个.NET Framework问题 . 共识是我的理解是正确的 - DataTable本身必须抛出 ObjectDisposedException . 除了它没有't. Not anywhere in the DataTable source code - hence my asking. I assumed that the framework would ensure an ObjectDisposedException after it had been disposed, which apparently isn' t的情况......不像GZipStream,它只允许在Dispose()之后访问两个方法,即DataTable DGAF . 精细 .

因此,让我重新解释一个问题:DataTable内部是否有任何内容可以轰炸我们,因为允许调用已分配的表?我可以假设微软似乎不是一个安全的假设 . 这段代码无论如何都会消失 - 我只想了解微软是否允许在 Dispose() 之后访问DataTable,或者是疏忽,而不是关心等等 .

此外,如果您投票或投票关闭它,请留下评论原因 .

3 回答

  • 5

    我认为除了程序员在 IDisposable.Dispose 实现中定义的内容之外,你还可以做任何事情 . 除了提供对 using 语句的支持之外,语言或框架不会做任何特殊操作 .

    使用 using 语句,该语言只提供以下内容:如果您的对象实现了名为 IDisposable 的特定接口,则它承诺在 using 块存在时调用 Dispose 方法 . 通过以特殊方式跟踪处置的物体,'s it. It has no knowledge of which objects have been 1360841 or not. It doesn' t抛出 ObjectDisposedException .

    是什么抛出 ObjectDisposedException ?那么,实现 IDisposable 类型的程序员需要在那里的某处编写这样的代码:

    void DoMoreWork()
    {
        if(_iHaveBeenDisposedAlready) 
            throw new ObjectDisposedException(null);
        ...
    

    所以在你的情况下,如果 ValidationDataTable 以一种在内存中没有数据的方式实现,那么它将像往常一样工作 . 语言或框架并不能阻止这种情况发生 .


    更新:回答评论,它看起来像 DataTable 不直接实现 IDisposable 但它的基类( MarshalByValueComponent )确实如此 . 他们必须继承该基类才能支持WinForms设计师的体验 . 在设计模式之外, Dispose 不需要在 using 块中使用它 .

    这是正常的吗?不可以 . 通常情况下, IDisposable 对象应放置在正常生命周期的某个地方 . 有一个不需要处理的 IDisposable 肯定令人困惑 .

  • 0

    正如Lee在评论中指出的那样,DataTable是一次性的,因为它继承了MarshalByValueComponent . Dispose()本身并不是一个意外事故,但没有什么能阻止框架的后续版本做一些确实导致异常的事情 .

    我认为依靠这个是一个坏主意,我会在包装它的使用中移动使用DataTable的代码 .

  • -4

    根据documentation on using

    通常,当您使用IDisposable对象时,您应该在using语句中声明并实例化它 . using语句以正确的方式调用对象上的Dispose方法,并且(如前所示使用它时)一旦调用Dispose,它也会导致对象本身超出范围 . 在using块中,该对象是只读的,不能修改或重新分配 .

    • 是的 . 见报价下面 .

    • 不适用

    • 不适用 . 如果查看IDisposable.Dispose(),则表明"Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources."如果可以在没有托管资源的情况下提供功能,则不需要配置对象来阻止访问该功能 .

    • 实现了您正在访问的方法或属性的类的开发人员添加了代码以检测对象是否已被处置并根据需要抛出异常 .

    也来自documentation on using

    您可以实例化资源对象,然后将变量传递给using语句,但这不是最佳做法 . 在这种情况下,在控制离开使用块之后,对象仍然在范围内,即使它可能不再能够访问其非托管资源 . 换句话说,它将不再完全初始化 . 如果您尝试使用using块之外的对象,则可能会导致抛出异常 . 因此,通常最好在using语句中实例化对象,并将其范围限制为using块 .

    简而言之, validationTable 已被释放,不再可以访问其非托管资源,但托管资源(数据的本地副本)仍然可用 . 假设 ValidationDataTable 已正确实施 . 由于我没有通过谷歌或msdn找到它,我假设它是一个内部类,所以任何事情都有 .

相关问题