A lot of the work I've been doing lately with .NET eventing and stuff comes down to the concept of resource-management - like how do we manage our resources' lifecycles without causing unintended negatives (like memory-leaks or performance issues). On the face of it resource-management is a problem of pluses and minuses, creating and releasing resources per their need - but the fact is, with frameworks like .NET there is so much resources creation and disposing going-on that we figuratively end up managing needles above a haystack.
The Idea: Take'em down with me
More to the point, I have this idea of managing the disposing of resources by creating a persuado supporter-dependent hierarchy of resources - sounds fancy but it is really simple. And the other part of the equation is having an API that isn't too intrusive - this is quite important to me, as I think with tiresome APIs the usefulness whether-away like a new-year's resolution.
In practical terms the disposing of resources is based around this single interface, called IDisposeRelated - which has the following make-up:
1: public interface IDisposeRelated
2: {
3: event EventHandler DisposeRelated;
4: }
Basically, you introduce this interface on any object that wants to limit the lifespan of one or more dependent resources to no more than its own - so good candidates include user controls object or event handlers. For example we could, append the IDisposeRelated interface as such:
1: public partial class Window1 : UserControl, IDisposeRelated
2: {
3: public event EventHandler DisposeRelated; // IDisposeRelated Members
4:
5: public Window1()
6: {
7: InitializeComponent();
8: this.Closing += (s, e) =>
9: {if (this.DisposeRelated != null) DisposeRelated(this, EventArgs.Empty);};
10: }
11: }
All we are saying here is that when closing the user control raise the DisposeRelated event, indicating that you want dependent resources to be brought-down too. Do note, I don't use the word "dispose" in the strict sense as with the IDisposable interface, which relates it to releasing unmanaged resources.
Dependent Resources: Proactively com'n down
Once we have the IDisposeRelated resource defined, we indicate the dependency using (mainly) extension methods - consider two examples:
1: this.Writer = new StreamWriter(_filePath).DisposeWith(this);
2: // or
3: ParentWindow.LostFocus +=
4: new RoutedEventHandler(ParentWindow_LostFocus).DisposeWith(this);
In line1 we are creating a new stream writer, to which we append the "DisposeWith" extension method to indicate that it should be disposed off when disposing "this". And "this" would/could be any object supporting the IDisposeRelated interface - so in other words, because the IDisposeRelated interface indicates as to when it wants to dispose related resources, we listen to that and take down any earmarked resources with it. And that's it.
The Take Down
Now, when I say "take-down" resources - the garbage collector would stare blankly first, but basically we know how to do certain stuff like with IDisposable objects we will call the Dispose method or with event handlers we can unregister it. For other stuff or when you want more control you can use another DisposeWith extension method definition that takes an action delegate (with the target passed in) to effect the "take-down" as you specify. For example:
1: var _cache = new MemoryCache().DisposeWith(this, (c) => c.Clear());
In the case of the cache object above, the "take-down" concept in its context would mean clearing whatever is in the memory. The point being, if we can proactively add this instruction of how to redeem resources whilst creation (though you could still add these instructions later) we won't loose the proverbial needle in the haystack. Further, by earmarking resources by the "dispose with" instruction, we create this persuado supporter-dependent hierarchy.
Technically Speaking
Having specified "dispose with" for an object does not preclude you from disposing it earlier - just later if it hasn't been disposed then it will do it for you. Secondly, the "dispose with" instruction only holds a weak reference to its target, and so it doesn't itself become a memory leak source. Also, you could possibly have more than "dispose with" instructions against a resource and it will be fulfilled in a first-come first-serve basis. Further, the dispose with thing doesn't have to be based on a resource's parent's lifecycle, it could be based on a peer object or on some other domain context - which is why I said a persuado supporter-dependent relationship and not a parent-child one.
Performance-wise, I've not checked because I am still mulling over the validity of the idea. But, I don't think it would be too great of hit, because my current implementation is basically adding a weak handler against the "DisposeRelated" event. All the same, there are other ways to implement the same functionality, so we'll see about the performance.
This current implementation is very basic, possibly in the future, if it is worthy, we could add fancy features like LINQ based dependency evaluation or lazily attach it with a control's lifecycle. For now, it is something simple I am trying in my code, but like in a lot of cases ideas as these comes down to the usefulness v/s inconvenience of the feature.
Posted by Rishi on 31-Jul-09 6:33 AM, 23 Comments