首页 > 解决方案 > 如何在 C# 类的具体实现上调用 Dispose

问题描述

如果我使用以下结构:

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对象上的 dispose 函数。

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

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

我知道我也可以围绕这个包装一个界面,但是还有其他方法吗?

标签: c#dispose

解决方案


当显式实现接口时会发生这种情况。首先,一个隐式实现接口的基本示例:

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类显式实现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。如果可以,它会处理,否则它什么也不做。


为什么这很有用可能看起来很奇怪,而且在您的情况下似乎不太必要。显式实现仅在类实现具有冲突接口成员的多个接口时才有用,例如:

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方法,因此您将面临错误。这是解决另一个问题(即重叠接口)的结果。


推荐阅读