c# - 使用 IDispose 关闭非托管资源
问题描述
我正在使用第 3 方数据库库在 C# 数据库中写入一些表:Esri file-geodatabase-api。对于每种表类型,我都实现了一个编写器类。我将对数据库对象的引用传递给每个作者。然后每个写入器在数据库中打开自己的表。
数据库和表类(第 3 方)都有 Close() 方法。他们还实现了 IDisposable!?根据 Esri 示例,我应该调用 Close()。
这是我的代码的简化版本。我在这里做事吗?来自 C++ 的自动垃圾收集让我感到困惑。
public class TableWriter : IDisposable
{
// Geodatabase is a 3rd party class that implements IDisposable and has Close() method:
private Geodatabase geoDatabase_;
// Table is a 3rd party class that implements IDisposable and has Close() method:
protected Table table_;
private string tableName_;
private bool disposing_;
public TableWriter(Geodatabase geoDatabase, string tableName)
{
geoDatabase_ = geoDatabase;
tableName_ = tableName;
disposing_ = false;
}
// Constructors of subclasses calls this:
public void CreateTable(List<FieldDef> fieldDefList)
{
table_ = geoDatabase_.CreateTable(tableName_, fieldDefList.ToArray(), "");
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed_)
{
return;
}
if(disposing) // called by user and not garbage collector
{
table_.Close();
table_.Dispose(); // can/should I do both Close and Dispose?
geoDatabase_ = null; // decrement reference count?
}
disposed_ = true;
}
// subclasses override this (they cast TableRow to a subtype):
public virtual void Write(TableRow tableRow){}
}
导出到数据库是从 gui 触发的。当我按顺序多次运行此导出时,我遇到了崩溃。我已经使用 Dispose 模式重写了我的代码,但还没有成功触发崩溃。崩溃似乎有点随机。有时我可以连续运行 5 次而不会崩溃,有时我可以连续运行 15 次而不会崩溃。崩溃的堆栈是这样的:
[19352] Exception Details: Cannot access a disposed object. Object name: 'Geodatabase'.
[19352] at Esri.FileGDB.Geodatabase.get_NativeGeodatabase()
[19352] at Esri.FileGDB.Table.Shutdown()
[19352] at Esri.FileGDB.Table.Dispose(Boolean A_0)
对我来说,似乎垃圾收集器调用了自动代码,它双重删除了其中一位作者中的一个表。
解决方案
首先,让你的课sealed
。与非密封类型相比,类型的实现规则要IDisposable
简单得多sealed
(例如,您不需要Boolean disposing
参数)。
然后,Dispose
像这样实现:
public void Dispose()
{
this.table_.Close();
GC.SuppressFinalize(this);
}
虽然您的问题的根本原因是您的Esri.FileGDB
库的Dispose
方法不是幂等的(即Dispose()
永远不应该抛出调用-多次ObjectDisposedException
调用单个实例应该总是安全的)。Dispose()
我假设您的数据库库还公开了错误调用的终结器(析构函数).Dispose()
或.Close()
导致ObjectDisposedException
.
推荐阅读
- json - 将带有产品名称的产品图像从 xamarin 表单上传到 Web api
- postgresql-12 - 下载PostgresSQL12版本后连接问题
- postgresql - 收到交易确认,但表格仍为空
- c - 如何从 bytea 获取 BYTE?
- html - 将样式化的 HTML 表格粘贴到 Microsoft Word 中的问题
- git - 获取旧版本代码并创建新分支后,无法理解 git 的消息
- javascript - Javascript代码无法在Django模板中使用模板继承
- c - 从 float 转换为 double 并返回到 float(未优化)是否保证返回相同的值?
- javascript - vue.js 中的 Intersection Observer 问题
- javascript - 如何以 JSON 格式下载带有 blob 的 VUEX 商店