如何在 C# 的具体实现上调用 Dispose class

How to call Dispose on a concrete implemenation of a C# class

如果我使用以下结构:

public class TestClass : IDisposable
{
    private SqlBulkCopy _bulkCopy;
    public TestClass(SqlConnection connection)
    {
        _bulkCopy = new SqlBulkCopy(connection);
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_bulkCopy != null)
                _bulkCopy.Dispose(); // Cannot call dispose as this is a concrete implementation
        }
    }
}

我无法访问我的 _bulkCopy 对象上的处置函数。

我知道我可以使用 using 语句,但这是唯一的方法吗?

我不想这样做,因为这意味着我可能不得不继续重新创建该对象

我知道我也可以围绕它包装一个接口,但还有其他方法吗?

这可能会发生 when an interface is explicitly implemented。首先,隐式实现接口的基本示例:

public interface IFoo
{
    void FooTheBar();
}

public class ImplicitImplementer : IFoo
{
    public void FooTheBar()
    {
        // ...
    }
}

这可以按照您期望的方式使用,具体类型和接口:

ImplicitImplementer a = new ImplicitImplementer();
a.FooTheBar(); // works

IFoo b = new ImplicitImplementer();
b.FooTheBar(); // works

但是当您显式实现接口时,您必须使用接口类型。

public class ExplicitImplementer : IFoo
{
    public void IFoo.FooTheBar()  // Notice the "IFoo."
    {
        // ...
    }
}

注意后果:

ExplicitImplementer a = new ExplicitImplementer();
a.FooTheBar(); // ERROR!

IFoo b = new ExplicitImplementer();
b.FooTheBar(); // works

这就是它的工作原理。我怀疑您的 SqlBulkCopy class 显式实现了 IDisposable,这意味着您必须将其转换为正确的接口:

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        if (_bulkCopy != null)
            (_bulkCopy as IDisposable).Dispose();
    }
}    

我更喜欢 as 语法,但如果您愿意,也可以使用 (IDisposable) _bulkCopy。实际上,您可以在此处稍微改进代码流程:

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        (_bulkCopy as IDisposable)?.Dispose();
    }
}

这可以防止在 _bulkCopy 为 null 或 _bulkCopy 不再实现 IDisposable 的情况下出现异常。如果可以,它会处理,否则什么都不做。


为什么这有用,这似乎很奇怪,而且在您的情况下似乎也没有必要。显式实现仅在 class 实现具有冲突接口成员的多个接口时才有用,例如:

public interface IFoo
{
    void FooTheBar();
}    

public interface IBar
{
    void FooTheBar();
}

public class FooBar : IFoo, IBar
{
    public void FooTheBar()
    {
        Console.WriteLine("IFoo or IBar?");
    }
}

此代码确实有效,但无论您是否这样做,都会调用相同的方法:

IFoo a = new FooBar();
a.FooTheBar(); // "IFoo or IBar?"

IBar b = new FooBar();
b.FooTheBar(); // "IFoo or IBar?"

但是如果你想让这两种方法分开怎么办?好吧,然后您将每个方法实现显式标记为属于特定接口。这就是显式实现。

public class FooBar : IFoo, IBar
{
    public void IFoo.FooTheBar()
    {
        Console.WriteLine("IFoo");
    }

    public void IBar.FooTheBar()
    {
        Console.WriteLine("IBar");
    }
}

然后你会看到:

IFoo a = new FooBar();
a.FooTheBar(); // "IFoo"

IBar b = new FooBar();
b.FooTheBar(); // "IBar"

但是由于您已将这些方法限制为特定接口,FooBar 本身无法再解析为特定 FooTheBar 方法,因此您会遇到错误。这是解决另一个问题(即重叠接口)的结果。