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

Rey*_*ldi 7 .net c#

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

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

}       
Run Code Online (Sandbox Code Playgroud)

在第一个构造函数上,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);
    }

}       
Run Code Online (Sandbox Code Playgroud)

ang*_*son 9

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

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

那么是的,你需要有一种机制来分辨这两种情况.

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

private MyProp _prop;        
private bool _ownsProp = false;
Run Code Online (Sandbox Code Playgroud)

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


如果你有大量的这些字段,每个字段必须有自己的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);
    }
}
Run Code Online (Sandbox Code Playgroud)