C#中的IDisposable实现 - 可以选择处理注入的IDisposable吗?

时间:2013-10-21 04:15:29

标签: c# idisposable

如果我有一个相当标准的抽象类,它允许注入一个IDisposable实例。但是,从此类继承的某些类不应该像其他类一样处理注入的存储库。显而易见的解决方案是使用构造函数:

public abstract class WorkspaceViewModel : IDisposable
{
    readonly bool _cascadeDisposeRepository;
    protected WorkspaceViewModel(IRepository repository, bool cascadeDisposeRepository=true)
    {
        _repository = repository;
        _cascadeDisposeRepository = cascadeDisposeRepository;
    }

修改

我还有一个带

的构造函数
    protected WorkspaceViewModel()
        :this(new RepositoryA(), true){} 

结束修改

然后在recomended microsoft manner

中实现Dispose方法
protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            if (_cascadeDisposeRepository) { _repository.Dispose(); }
            .....

但是,我从未见过以这种方式实现IDisposable,并且想知道这是不好的做法(如果是,为什么,以及其他什么解决方案更可取)。

感谢您的想法。

修改 Mark的评论让我意识到优选的实现可能没有无参数构造函数,强制从WorkspaceViewModel继承的任何类创建和配置它们自己的实例(并选择实现IDisposable),同时从WorkspaceViewModel的已实现接口中删除IDisposable。 p>

2 个答案:

答案 0 :(得分:1)

由于您没有非托管资源的句柄,我建议完全删除IDisposable。

由于您的类是一个存储库,我怀疑它使用的数据库连接可能间接地处理非托管资源 - 所以只需记住将其包装在一个使用中:

using(var myConn = new Connection(connectionString))
{
}

然后你可以让托管代码的美丽担心什么可以破坏和保持活着 - 你甚至不需要考虑它。

答案 1 :(得分:0)

“使用”实现IDisposable的对象的最后一个实体,通过直接访问它或将其传递给已知持续时间临时使用的其他实体,应该调用{ {1}}就可以了。如果Dispose从某个其他实体传递Moe,而该实体本身就知道Moe何时完成,那么Moe通常可以期望其他实体处理它而不需要调用IDisposable本身。实际上,在Moe完成之后,其他实体可能会使用Dispose,然后Moe必须调用IDisposable本身。如果Dispose传递了接口或基类类型的引用,则不需要接口或基类来实现Moe;即使传入的实例可能是实现IDisposable的派生类型,这也不是Moe的关注点。创建该实例的实体应该知道它是一个实现IDisposable并处理它的类型。

事情变得棘手的地方是工厂方法。如果有一个实际的可能性,工厂方法可能会返回一个实现IDisposable的对象,并且该方法的调用者将是唯一知道何时不再需要该对象的东西,那么返回类型为方法本身应该实现IDisposable。由于非通用IDisposable接口不遵循该模式,因此需要使用非通用IEnumerator接口的代码来检查IEnumerable实现GetEnumerator()返回的每个对象如果是这样,请致电IDisposable;这比Dispose无条件地调用IDisposable更不方便和慢[[1}} [即使只有99.9%的IEnumerator实现会有无效IEnumerator方法,调用一个接口已知支持的do-nothing方法比检查接口是否支持方法更快]。 请注意,使用工厂方法的返回类型实现或继承Dispose不会给调用者添加任何责任 - 这只会使调用者更容易履行他们将拥有的责任