When you are working with hierarchies of objects, you sometimes run into situations where you need to properly dispose of an object. Not only will you need to dispose of that object, but you likely will need to walk the object tree and recursively dispose of children of that object. To do this, we typically implement the IDisposable pattern and manually code the steps required to shut down the desired objects, and call the Dispose() method on other children objects. This cascading of disposals takes a lot of effort and it is prone to mistakes and omissions.
The DisposableAttribute aspect relies on the AggregatableAttribute aspect and, as a result, is able to make use of the VisitChildren(ChildVisitor, ChildVisitorOptions, object) method to cascade disposals through child objects.
Disposing of object trees
To automatically implement the IDisposable interface:
Add a reference to the
PostSharp.Patterns.Model
package.On the top level object add the DisposableAttribute.
Annotate the object model as described in Parent/Child, Visitor and Disposable.
Note
Fields that are marked as children but are assigned to an object that does not implement IDisposable (either manually or through DisposableAttribute) will simply be ignored during disposal.
Note
Items of child collections will be automatically disposed of as well unless items of child collections are considered as references. See Working With Child Collections for details.
Example
In this example, the HomeMadeLogger
class has two fields, _stream
and _textWriter
, which should also be disposed of when the HomeMadeLogger
is disposed of.
[Disposable]
public class HomeMadeLogger
{
[Child]
private TextWriter _textWriter;
[Child]
private Stream _stream;
[Reference]
private MessageFormatter _formatter;
public HomeMadeLogger(MessageFormatter formatter)
{
_formatter = formatter;
_stream = new FileStream("our.log", FileMode.Append);
_textWriter = new StreamWriter(_stream);
}
public void Debug(string message)
{
_textWriter.WriteLine(_formatter.Format(message));
}
}
The _stream
and _textWriter
child objects will now have their Dispose()
method called automatically when the HomeMadeLogger
is disposed of. Since both the _stream
and _textWriter
objects are framework types that already implement IDisposable, adding the DisposableAttribute aspect to those object types is not necessary.
Customizing the Dispose logic
There will be times when you have objects that need custom disposal logic. At the same time, you may want to implement a parent child relationship and make use of the DisposableAttribute. PostSharp allows you to combine custom and automatic logic.
To add your own logic to the Dispose
method, create a method with exactly the following signature:
protected virtual void Dispose( bool disposing )
{
}
Warning
The DisposableAttribute aspect does not automatically dispose of the object when it is garbage collected. That is, the aspect does not implement a destructor. If you need a destructor, you have to do it manually and invoke the Dispose
.
Example
In the following example, we are customizing the Dispose pattern to expose the IsDispose
property:
[Disposable]
public class HomeMadeLogger
{
public bool IsDisposed { get; private set; }
protected virtual void Dispose( bool disposing )
{
this.IsDisposed = true;
}
}
Once you have done this, PostSharp will properly run your custom Dispose logic as well as running any of the parent and child implementations of the DisposableAttribute that exist for the object.