2014-09-02 91 views
6

我有关于处理对象的问题。如何正确处理对象:注入还是拥有对象

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

}  
+3

我喜欢第二种方法。处理你还没有创建的对象可能会在以后导致各种令人讨厌的惊喜。 – Dirk 2014-09-02 07:36:26

+0

听起来很像http://stackoverflow.com/questions/4085939/who-should-call-dispose-on-idisposable-objects-when-passed-into-another-object?rq=1 – 2014-09-02 07:38:00

+0

@DmitryBychenko因为这会当它被注入时也是“真实的”,他需要别的东西(比如那个布尔值)来告诉两种情况。 – 2014-09-02 07:38:19

回答

9

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

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

然后是的,你需要有一个机制,告诉这两种情况分开。

的常用方法(反正共同我)是使用的命名规则是这样的:

private MyProp _prop;   
private bool _ownsProp = false; 

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


如果你有一吨的这些领域,在那里每个人都必须有自己的布尔场来处理这个的,它可能是值得创建一个辅助类,比如这个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); 
    } 
} 
+0

请注意,我的命名约定会使用大写的第一个字符,但我为此答案采用了您的套接字约定,但“OwnsX”约定仍然是我要使用的。 – 2014-09-02 07:39:06

+0

有没有更详细的解决方案?在我的情况下,我使用了很多注入属性。特别是对于测试 – Reynaldi 2014-09-02 07:44:25

+0

但他们都将被单独注入或拥有?意思是,假设您有3个这样的对象,将会注入* all *或创建* all *,或者可以注入任何对象组合并在内部创建其他对象?如果是后者,那么不是,你需要每个字段有一个这样的值,尽管你当然可以把它包装到一个帮助类中。如果前者类型,那么你需要区分* all * inject或* all *创建,这只需要一个这样的值。 – 2014-09-02 07:50:43

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

配置调用过程中通过流对象,实际上是sence。

在其他情况下,是的,最好不要销毁对象,如果你不是它的拥有者。留给呼叫者决定何时适合做这件事。