关于这个问题有很多关于SO的问题,但我还没有找到一个涵盖我特别需要理解的问题。
我的一位开发人员编写了这段代码:
//
// 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但已经处理掉了但没有进行垃圾回收 - 但仍然应该在ObjectDisposedException
调用上抛出.ToDictionary()
。但是这段代码很乐意构建一个有效的字典并继续前进。
我有理论,但找不到确定或击落其中任何一个的确定性。并且可以通过十几种方式重写代码以避免问题;这不是问题。我只需要知道我理解的差距是什么。
我的问题:
DataTable
的特定内容允许在放置对象后进行访问 - 类似于GZipStream
类要求您处理对象以刷新流的方式,因此允许调用在对象被处置后到.ToArray()
和.GetBuffer()
?
澄清:
这是一个.NET Framework问题。共识是我的理解是正确的 - DataTable本身必须抛出ObjectDisposedException
。除了它没有。不是DataTable源代码中的任何地方 - 因此我的要求。我假设框架将在它被处理之后确保一个ObjectDisposedException,这显然不是这种情况......不像GZipStream,它只允许在Dispose()之后访问两个方法,即DataTable DGAF。精细。
所以让我重新解释一下这个问题:DataTable内部是否有任何内容可以轰炸我们,因为允许调用已处置的表?我可以假设微软没有在内部清理任何东西,只要对象在范围内,所有属性和值都将保持不变,这似乎不是一个安全的假设。这段代码无论如何都会消失 - 我只是想了解微软是否允许在Dispose()
之后访问DataTable,或者是疏忽,而不是关心等等。
此外,如果您投票或投票关闭它,请发表评论原因。
答案 0 :(得分:5)
我认为你缺少的部分是“处理”一个对象除了程序员在IDisposable.Dispose
实现中定义的内容之外没有做任何事情。除了为using
语句提供支持之外,语言或框架不会做任何特殊操作。
使用using
语句,语言只提供以下内容:如果您的对象实现了名为IDisposable
的特定接口,那么它承诺在Dispose
方法存在时调用using
方法{ {1}}阻止。而已。它不知道哪些物体已被“处置”或没有。它不会以特殊方式跟踪已处置的对象而抛出ObjectDisposedException
。
什么会引发ObjectDisposedException
?那么,实现IDisposable
类型的程序员需要在那里的某处编写这样的代码:
void DoMoreWork()
{
if(_iHaveBeenDisposedAlready)
throw new ObjectDisposedException(null);
...
因此,在您的情况下,如果ValidationDataTable
的实现方式无法跟踪它是否被处理,并且它将数据存储在内存中,那么它将像往常一样工作。语言或框架并不能阻止这种情况发生。
更新:要回答评论,看起来DataTable
不会直接实现IDisposable
,但它是基类(MarshalByValueComponent
)。他们必须继承该基类才能支持WinForms设计师的体验。在设计模式之外,Dispose
不会改变任何东西。因此,您可以安全地忽略它以供正常使用。换句话说,您不需要在using
块中使用它。
这是正常的吗?不可以。通常,IDisposable
个对象意味着要放置在正常生命周期的某个地方。如果IDisposable
不需要处理,那肯定会让人感到困惑。
答案 1 :(得分:0)
Lee在评论中指出,DataTable是一次性的,因为它继承了MarshalByValueComponent。 Dispose()不会做任何会导致稍后抛出Disposed异常的事故。好吧,它本身并不是一个意外,但没有什么可以阻止更高版本的框架执行做引起异常的事情。
我认为依靠这个是一个坏主意,我会移动使用DataTable的代码来包装它。
答案 2 :(得分:-4)
根据EPEL:
通常,当您使用IDisposable对象时,您应该在using语句中声明并实例化它。 using语句以正确的方式调用对象上的Dispose方法,并且(如前所示使用它时)一旦调用Dispose,它也会导致对象本身超出范围。在using块中,该对象是只读的,不能修改或重新分配。
using
,它会声明“执行与释放,释放或重置非托管资源相关的应用程序定义的任务”。如果可以在没有托管资源的情况下提供功能,则不需要配置对象来阻止访问该功能。您可以实例化资源对象,然后将变量传递给using语句,但这不是最佳做法。在这种情况下,在控制离开使用块之后,对象仍然在范围内,即使它可能不再能够访问其非托管资源。换句话说,它将不再完全初始化。如果您尝试使用using块之外的对象,则可能会导致抛出异常。因此,通常最好在using语句中实例化对象,并将其范围限制为使用块。
简而言之,validationTable
已被释放,无法再访问其非托管资源,但托管资源(数据的本地副本)仍然可用。假设ValidationDataTable
已正确实施。由于我没有通过google或msdn找到它,我假设它是一个内部类,所以任何事情都会发生。