How to properly dispose of objects: injected against the owner

I have a question about recycling objects.

Consider this IDisposable Class

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

The first constructor introduces MyProp . Therefore, MyClass does not own the object. But on the second constructor, MyProp is created locally. Should I always position MyProp , or should I first check if it is entered or not.

 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); } } 
+6
source share
2 answers

If your class should handle these two situations:

  • This is not the owner of the provided object, he should not dispose of it.
  • This is the owner of the created object, he must dispose of it.

Then yes, you should have a mechanism that describes these two situations.

The usual method (common to me anyway) is to use a naming convention as follows:

 private MyProp _prop; private bool _ownsProp = false; 

T. Change the meaning of your flags, but these are the details, your decision is just perfect, and yes, you need to have such a solution.


If you have a ton of these fields where everyone needs to have their own bool field to handle this, it might be worth creating a helper class, for example LINQPad demonstrates:

 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); } } 
+9
source

Another note may also be made here.

It depends on what your MyClass does.

For example, if we are talking about a class that reads a video stream from a device, after applying some filters to it and writing data to a file specified by the user, where the file is written by the stream transferred from the outside, let's say this:

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

deleting the passed stream object during a call makes the actual value.

In other cases, yes, it’s best not to destroy the object unless you own it. Leave this to the caller to decide when is the right time for this.

0
source

Source: https://habr.com/ru/post/974677/


All Articles