c# - 使用 IDispose 关闭非托管资源

标签 c# esri

<分区>

我正在使用第 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){}
}

导出到数据库是从图形用户界面触发的。 当我按顺序多次运行此导出时,我遇到了崩溃。 从那以后,我使用 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)

在我看来,垃圾收集器调用了自动代码,双倍删除了其中一位作者的表。

最佳答案

首先,让您的类密封。与非密封类型相比,IDisposable 的实现规则对于密封 类型要简单得多(例如,您不需要Boolean disposing 参数)。

然后,像这样实现Dispose:

public void Dispose()
{
    this.table_.Close();
    GC.SuppressFinalize(this);
}

虽然您的问题的根本原因是您的 Esri.FileGDB 库的 Dispose 方法不是幂等的(即 Dispose() 调用永远不应抛出 ObjectDisposedException - 多次调用单个实例的 Dispose() 应该始终是安全的。

我假设您的数据库库还公开了错误调用 .Dispose().Close() 方法的终结器(析构函数),这些方法随后导致 ObjectDisposedException.

关于c# - 使用 IDispose 关闭非托管资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57605158/

相关文章:

c# - Typemock - 物有所值?

C# Mongo 查询效率

c# - float.TryParse() 四舍五入 C# 中的值

java - 用一组要求的点进行距离计算

mysql - ArcGIS 中不需要的 varchar 到 BLOB 转换

c# - wp7音乐播放器

c# - 尝试使用 OOPFactory 解析使用 EligibilityBenefitDocument 的 271 个好处

sql-server-2008 - 如何将 ESRI Shape 文件转换为 SQL Server 2008?

python - 如何使用 QGIS 或 python gdal 库转换 ESRI shapefile 格式以提取纬度

javascript - 从 Extent 对象中提取纬度和经度