How to release anonymous delegates / closures correctly in C#?
I'm working on a GUI application, which relies heavily on Action<>
delegates to customize behavior of our UI tools. I'm wondering if the way we are doing this has any potential issues, e.g. whether the implementation keeps references to captured variables, class instances that declare the delegates etc?
So let's say we have this class MapControl
, which wraps a stateful GUI control. The map has different kinds of tools (Drawing, Selection, etc.), represented by ITool
interface. You can set the tool with StartTool()
, but you can only have one tool active at a time, so when another tool is set previous one is stopped using StopTool()
. When tool is stopped, a caller-specified callback delegate is executed.
public class MapControl
{
ITool _currentTool;
Action<IResult> _onComplete;
public void StartTool(ToolEnum tool, Action<IResult> onComplete) {
//If tool is active, stop it first
if (_currentTool != null) StopTool();
_onComplete = onComplete;
//Creates a tool class, etc.
_currentTool = CreateTool(tool) as ITool;
}
public void StopTool() {
//Execute callback delegate
IResult result = _currentTool.GetResult();
if (_onComplete != null)
_onComplete(result);
//Nix the references to callback and tool
_onComplete = null;
_currentTool = null;
}
}
In the application's 开发者_开发百科ViewModel
class we set some tool like this:
class ViewModel
{
private MapControl _mapControl = new MapControl();
public void SetSomeTool()
{
//These variables will be captured in the closure
var someClassResource = this.SomeClassResource;
var someLocalResource = new object();
//Start tool, specify callback delegate as lambda
_mapControl.StartTool(ToolEnum.SelectTool, (IResult result) => {
//Do something with result and the captured variables
someClassResource.DoSomething(result, someLocalResource);
});
}
}
In our case the ViewModel
class is attached to the main window of a WPF application, and there can only be one instance of ViewModel
during the application lifetime. Would it change anything if this weren't the case, and the classes which declare the delegates would be more transient?
My question is, am I disposing of the callback delegates correctly? Are there any scenarios, where this can cause memory bloat by holding on to references it shouldn't?
More generally, what's the safe and correct way of disposing anonymous delegates?
IMHO, it is ok and you are not holding on to any references you don't need. With clearing the references in StopTool you no longer hold them.
You are doing fine with removing the Reference to methods that way.
One more thing you asked:
My question is, am I disposing of the callback delegates correctly?
You don't dispose methods (or pointers to methods for that matter), only classes.
I think a more proper way would be:
_onComplete = (Action<IResult>)Delegate.Remove(null, _onComplete);
If you want to make sure you are disposing correctly of all unused objects, I'd suggest you use tools like the CLR Profiler so that you can have a complete view of how your application is allocating/freeing memory.
精彩评论