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

本文关键字:注入 拥有 对象 正确处理 | 更新日期: 2023-09-27 18:20:22

我有一个关于处理对象的问题。

考虑这个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);
    }
}       

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

如果您的类应该处理以下两种情况:

  1. 它不是所提供对象的所有者,不应该处理它
  2. 它是创建的对象的所有者,应该处理它

那么,是的,你需要有一个机制来告诉这两种情况。

一个常见的方法(对我来说很常见)是使用这样的命名约定:

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);
    }
}

这里也可以做不同的注释。

这取决于你的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
    }   
}

在dispose调用期间处理传递的流对象,实际上会产生sence。

在其他情况下,是的,如果您不是对象的所有者,最好不要销毁该对象。让调用者来决定何时是销毁对象的合适时机。