如何正确处理对象:注入与拥有

时间:2014-09-02 07:34:30

标签: c# .net

我对处理对象有疑问。

考虑这个IDisposable

public class MyClass : DisposableParentClass
{
    private MyProp _prop;        

    public MyClass(MyProp prop)
    {
        _prop = prop;
    }

    public MyClass()
    {            
        _prop = new MyProp();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _prop.Dispose();
        }

        base.Dispose(disposing);
    }

}       

在第一个构造函数上,注入了MyProp。所以MyClass不是对象的所有者。但是在第二个构造函数上,MyProp是在本地创建的。 我是否应该始终处置MyProp,或者我应该先检查它是否被注入。

public class MyClass : DisposableParentClass
{
    private MyProp _prop;        
    private bool _myPropInjected = false;

    public MyClass(MyProp prop)
    {
        _prop = prop;
        _myPropInjected = true;
    }

    public MyClass()
    {            
        _prop = new MyProp();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (!_myPropInjected) { _prop.Dispose(); }
        }

        base.Dispose(disposing);
    }

}       

2 个答案:

答案 0 :(得分:9)

如果你的班级应该处理这两种情况:

  1. 它不是所提供对象的所有者,不应该将其丢弃
  2. 它是创建对象的所有者,它应该处理它
  3. 然后是的,你需要有一种机制来区分这两种情况。

    一种常见的方法(无论如何我都是这样)是使用这样的命名约定:

    private MyProp _prop;        
    private bool _ownsProp = false;
    

    即。反转你的旗帜的含义,但这是细节,你的解决方案很好,是的,你需要有这样的解决方案。


    如果你有大量这些字段,每个字段都必须有自己的bool字段来处理这个字段,那么创建一个帮助类可能是值得的,例如这个LINQPad程序演示:

    void Main()
    {
        Injectable i1 = new Injectable();
        Injectable i2 = new Injectable(new Injected("A"));
        Injectable i3 = new Injectable(new Injected("A"), new Injected("B"));
    
        Debug.WriteLine("dispose a and b");
        i1.Dispose();
    
        Debug.WriteLine("dispose b");
        i2.Dispose();
    
        Debug.WriteLine("no dispose");
        i3.Dispose();
    }
    
    public class Injected : IDisposable
    {
        public Injected(string name) { Name = name; }
        public string Name { get; set; }
        public void Dispose() { Debug.WriteLine(Name + " disposed"); }
    }
    
    public class Injectable : IDisposable
    {
        private Ownable<Injected> _A;
        private Ownable<Injected> _B;
    
        public Injectable(Injected a, Injected b)
        {
            _A = Ownable.NotOwned(a);
            _B = Ownable.NotOwned(b);
        }
    
        public Injectable(Injected a)
        {
            _A = Ownable.NotOwned(a);
            _B = Ownable.Owned(new Injected("B"));
        }
    
        public Injectable()
        {
            _A = Ownable.Owned(new Injected("A"));
            _B = Ownable.Owned(new Injected("B"));
        }
    
        public void Dispose()
        {
            _A.Dispose();
            _B.Dispose();
        }
    }
    
    public class Ownable<T> : IDisposable
        where T : class
    {
        private readonly T _Instance;
        private readonly Action _CleanupAction;
    
        public Ownable(T instance, bool isOwned)
        {
            _Instance = instance;
    
            if (isOwned)
            {
                IDisposable disposable = instance as IDisposable;
                if (disposable == null)
                    throw new NotSupportedException("Unable to clean up owned object, does not implement IDisposable");
    
                _CleanupAction = () => disposable.Dispose();
            }
        }
    
        public Ownable(T instance, Action cleanupAction)
        {
            _Instance = instance;
            _CleanupAction = cleanupAction;
        }
    
        public T Instance { get { return _Instance; } }
    
        public void Dispose()
        {
            if (_CleanupAction != null)
                _CleanupAction();
        }
    }
    
    public static class Ownable
    {
        public static Ownable<T> Owned<T>(T instance)
            where T : class
        {
            return new Ownable<T>(instance, true);
        }
    
        public static Ownable<T> Owned<T>(T instance, Action cleanupAction)
            where T : class
        {
            return new Ownable<T>(instance, cleanupAction);
        }
    
        public static Ownable<T> NotOwned<T>(T instance)
            where T : class
        {
            return new Ownable<T>(instance, false);
        }
    }
    

答案 1 :(得分:0)

这里可以做出不同的说明。

这取决于你MyClass实际上做了什么。

例如,如果我们正在谈论从设备读取视频流的类,在对它应用一些过滤器并将数据写入用户指定的文件之后,其中文件写入是通过从外部传递的流来进行的,比如这样:

public class VideoProcessor : IDisposable {
    private FileStream _videoFile = null;
    private VideoProcessor() {}

    //user specified FileStream
    public VideoProcessor(FileStream fs) {_videoFile = fs;}

    public void Dispose() {
        _videoFile.Dispose(); //Dispose user passed FileStream
    }   
}
在配置调用期间配置传递的流对象,实际上就是这样。

在其他情况下,是的,如果你不是它的拥有者,最好不要销毁它。留给调用者来决定何时适合这样做。

相关问题