How to make sure not to dispose objects that are still used by others

大憨熊 提交于 2019-12-12 05:48:22

问题


I have a class that use constructor injections.

public class MyClass
{                       
    public MyClass(IInterface1 interface1)
    {            
    }

    public Dispose()
    {
       interface1.dispose();
    }
}

interface1 will be injected by DI. But sometimes, i need to create MyClass manually.

public class MyOtherClass
{                       
    private readonly IInterface1 _interface1;

    public MyOtherClass()
    {
      _interface1 = new Interface1();
    }       

    public Foo()
    {
       foo = new MyClass(_interface1);
       bar = new MyClass(_interface1);
    }
}

in my dispose method, interface1 is always disposed when MyClass is destroyed. The problem is, interface1 is own by MyOtherClass and might still be used by other instances and shouldn't be disposed. How can i resolve this?


回答1:


You should not call

interface1.dispose();

inside MyClass.

If interface1 is created by the DI container, it will be rleased there. If you are creating it explicitly as in MyOtherClass, Dispose it in MyOtherClass.




回答2:


There are two problems with your code.

First of all, MyClass 'illegally' takes the ownership of the IInterface1, while it has no idea what the lifetime of that instances is. This means that if IInterface1 is reused, the system breaks.

The basic rule of ownership is that "he who creates an instance is responsible of disposing it" (the RAII idiom). Since MyClass didn't create IInterface1, he should not dispose it. MyClass should therefore not implement a Dispose method and not call IInterface1.Dispose().

Second, by letting the IInterface1 implement IDisposable, your code violates the Dependency Inversion Principle (DIP), because the DIP states:

Abstractions should not depend on details. Details should depend on abstractions.

Your IInterface1 however, depends on an implementation detail, because whether or not some component has unmanaged resources that needs to be disposed is an implementation detail. It is very unlikely that every implementation of that IInterface1 will always need to dispose resources and because of that your interface leaks implementation details of a specific implementation.

So instead of letting the IInterface1 implement IDisposable you simply let the given implementation implement IDisposable. What's nice about this is that it minimized IInterface1's API, which makes it easier to work with and possibly allows you to conform to the Interface Segregation Principle.

If you do that, the problem goes away immediately, since MyClass has no clue whether or not IInterface1 can be disposed or not (which is good), which means it can't accidentally call Dispose in the first place.

This of course leaves the disposal of that instance up to the part of the system that created that instance (which is good). If this instance is created on your behalf by a DI library (if you use one), the DI library is usually responsible of disposing that instance. If you don't use a container, you will have to ensure disposal yourself obviously.

Do note that not all containers track all instances. For instance, Unity and Simple Injector do not track (and dispose) transient instances automatically. In most cases however, disposable components should be registered with a scoped lifestyle (per web request or something similar). I think in that case all containers dispose instances that are registered with such lifestyle.



来源:https://stackoverflow.com/questions/26753237/how-to-make-sure-not-to-dispose-objects-that-are-still-used-by-others

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!