在API

时间:2016-02-04 18:43:11

标签: c# .net api idisposable

我目前正在编写一个相当大的API,并且对于如何实现IDisposable感到困惑。在简化的场景中:

我的一个类中有一个Socket(称之为A),这显然需要处理,但是该类只有内部构造函数,因此我的用户只能通过创建实例来创建它的实例一个更高级别的对象(称为B),它将反过来实例化A,从而获得新对象A的所有权。

我的直觉建议使对象A和B都是IDisposable,这样当用户在他们的应用程序中处理我们拥有的对象B时,A被处理掉,套接字也被正确处理掉。但是,由于这是一个API,它允许我的用户在不丢弃拥有对象B的情况下处置对象A和套接字,因此可能会导致一些重大问题。

那我该怎么办?据我所知,我唯一的选择是糟糕的选择:

  1. 实现IDisposable,因为直觉会有它,并告诉我的用户不要在文档中愚蠢。 (非常糟糕)
  2. 实现IDisposable就像直觉一样,但在整个应用程序中添加一些可怕的处理检查/异常以防万一(尽管在我的应用程序中,处理整个子部分对应用程序来说无论如何都是致命的。)
  3. 仅在对象B中实现IDisposable,而是添加内部Dispose方法以安全地处置A和套接字。 (看似最好的主意)
  4. 我不确定我是否有其他选择,所以我真的希望有人能告诉我。

    感谢。

2 个答案:

答案 0 :(得分:2)

  

我的直觉建议使对象A和B都可以使用   当用户在他们的应用程序中处理我们拥有的对象B时,A   处理掉并且插座也被正确地处理掉。   但是,由于这是一个API,它将允许我的用户处置   对象A和套接字没有处理拥有对象B和   因此可能会引发一些重大问题。

使两个工具IDisposable可能是最好的想法,并清楚地说明需要清理代码实例的事实。指示API的使用者在根/拥有对象(B)上调用Dispose。为了解决API消费者的问题,我还要在拥有的(A)实例上调用Dispose,您可以执行以下操作。

隐藏

不要从root /拥有对象B公开拥有的引用A,或者提供有限数量的pass through方法,这些方法调用root并传递给拥有的实例然后再返回。如果您谈论的是真正有限数量的方法/属性不会改变,这很好。

<强>接口

使用包装器和接口包装套接字访问(我假设套接字是.net socket class但是如果它是你自己的套接字类的对象实现那么你的类已经是包装器了并且无需在周围创建另一个包装器。包装器应该实现IDisposable,接口应该只显示您希望客户端有权访问的内容。我不确定您在哪里创建套接字的实例,但它们应该由拥有的对象或使用工厂模式创建,以便在创建后尽快建立所有者关系。您可以将类定义保持在内部,只显示API的接口。

在我看来,这是最好的方法,如果您需要扩展API,可以在将来进行灵活的更改。

public class Owner : IDisposable
{
    private SocketWrapper _wrapper;
    public ISocketWrapper SocketAccess { get { return _wrapper; } }
    public void Dispose()
    {
        if (_wrapper != null)
            _wrapper.Dispose();
    }
}

public interface ISocketWrapper
{
    // exposed properties/methods
}


internal class SocketWrapper : ISocketWrapper, IDisposable
{
    public void Dispose()
    {
        // dispose socket
    }
}

答案 1 :(得分:0)

好吧,如果你不希望api用户处理你的套接字,而不是隐藏它(做一些包装器或套接字是私有的东西)。

否则,通常会像这样执行dispose,这样你就可以执行级联处理,如果已经处理了某些东西,你真的不介意。

public class ComplexResourceHolder : IDisposable {

private IntPtr buffer; // unmanaged memory buffer
private SafeHandle resource; // disposable handle to a resource

public ComplexResourceHolder(){
    this.buffer = ... // allocates memory
    this.resource = ... // allocates the resource
}

protected virtual void Dispose(bool disposing){
        ReleaseBuffer(buffer); // release unmanaged memory
    if (disposing){ // release other disposable objects
        if (resource!= null) resource.Dispose();
    }
}

~ ComplexResourceHolder(){
    Dispose(false);
}

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

}

代码示例取自msdn,您可在其中找到更详细的说明。