February 14, 2012

Executing Actions Before and After Code Blocks with IDisposable

I ran into a scenario this week where a boolean field was being flipped temporarily to modify behavior elsewhere while a block of code was executing.  I have seen this pattern mainly in WinForms applications where data are being loaded into controls, but their events need to be suppressed during the load.  Afterward, the events should fire normally.

Below is an example of this scenario.  It is a Windows form with a single combobox.  Whenever the selected value of the combobox changes, an expensive action is executed such as a database or service call.  During the loading of the form data, the possible values of the combobox are added, and the first item is selected.  This causes the expensive operation to execute unnecessarily.

    public partial class BeforeAndAfterTest : Form
    {
        public BeforeAndAfterTest()
        {
            InitializeComponent();
        }
    <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnLoad(EventArgs e)
    {
        LoadComboBoxData();

        <span class="kwrd">base</span>.OnLoad(e);
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> LoadComboBoxData()
    {
        comboBox.Items.Add(<span class="str">"Item 1"</span>);
        comboBox.Items.Add(<span class="str">"Item 2"</span>);
        comboBox.Items.Add(<span class="str">"Item 3"</span>);
        comboBox.Items.Add(<span class="str">"Item 4"</span>);

        comboBox.SelectedIndex = 0;
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> comboBox_SelectedIndexChanged(
        <span class="kwrd">object</span> sender, EventArgs e)
    {
        PerformExpensiveOperation();
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> PerformExpensiveOperation()
    {
        <span class="rem">// Imagine that this method performs an expensive operation</span>
        <span class="rem">// that doesn't need to execute when the form loads.</span>
        MessageBox.Show(<span class="str">"Expensive operation."</span>);
    }
}</pre>

A common fix for this issue is to add a boolean flag to indicate that the event action does not need to execute.

    public partial class BeforeAndAfterTest : Form
    {
        private bool _loading = false;
    <span class="kwrd">public</span> BeforeAndAfterTest()
    {
        InitializeComponent();
    }

    <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnLoad(EventArgs e)
    {
        <span class="highlight">_loading = <span class="kwrd">true</span>;</span>

        LoadComboBoxData();

        <span class="kwrd">base</span>.OnLoad(e);

        <span class="highlight">_loading = <span class="kwrd">false</span>;</span>
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> LoadComboBoxData()
    {
        comboBox.Items.Add(<span class="str">"Item 1"</span>);
        comboBox.Items.Add(<span class="str">"Item 2"</span>);
        comboBox.Items.Add(<span class="str">"Item 3"</span>);
        comboBox.Items.Add(<span class="str">"Item 4"</span>);

        comboBox.SelectedIndex = 0;
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> comboBox_SelectedIndexChanged(
        <span class="kwrd">object</span> sender, EventArgs e)
    {
        <span class="highlight"><span class="kwrd">if</span> (_loading)</span>
            <span class="highlight"><span class="kwrd">return</span>;</span>

        PerformExpensiveOperation();
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> PerformExpensiveOperation()
    {
        <span class="rem">// Imagine that this method performs an expensive operation</span>
        <span class="rem">// that doesn't need to execute when the form loads.</span>
        MessageBox.Show(<span class="str">"Expensive operation."</span>);
    }
}</pre>

This type of coding makes me nervous because a programmer could forget to wrap the updates to the boolean flag in a try {} finally {} block as in the previous example.  In the case that an exception is thrown, the flag will not be reset resulting in incorrect behavior.

A nice solution is to use a class that implements IDisposable to update the flag before and after the block of code is run.

    public class BeforeAndAfterBlock : IDisposable
    {
        private readonly Action _before;
        private readonly Action _after;
    <span class="kwrd">public</span> BeforeAndAfterBlock(Action before, Action after)
    {
        _before = before ?? <span class="kwrd">delegate</span> { };
        _after = after ?? <span class="kwrd">delegate</span> { };

        _before();
    }

    <span class="kwrd">public</span> <span class="kwrd">void</span> Dispose()
    {
        _after();
    }
}</pre>

The constructor takes two actions to execute.  One is executed immediately, and the other is executed in the Dispose() method.  With the C# using statement, the code becomes clear, concise, and most importantly, safer.

    public partial class BeforeAndAfterTest : Form
    {
        private bool _loading = false;
    <span class="kwrd">public</span> BeforeAndAfterTest()
    {
        InitializeComponent();
    }

    <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnLoad(EventArgs e)
    {
        <div class="highlight">            <span class="kwrd">using</span> (<span class="kwrd">new</span> BeforeAndAfterBlock(
            () =&gt; _loading = <span class="kwrd">true</span>, () =&gt; _loading = <span class="kwrd">false</span>))</div>
        {
            LoadComboBoxData();

            <span class="kwrd">base</span>.OnLoad(e);
        }
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> LoadComboBoxData()
    {
        comboBox.Items.Add(<span class="str">"Item 1"</span>);
        comboBox.Items.Add(<span class="str">"Item 2"</span>);
        comboBox.Items.Add(<span class="str">"Item 3"</span>);
        comboBox.Items.Add(<span class="str">"Item 4"</span>);

        comboBox.SelectedIndex = 0;
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> comboBox_SelectedIndexChanged(
        <span class="kwrd">object</span> sender, EventArgs e)
    {
        <span class="kwrd">if</span> (_loading)
            <span class="kwrd">return</span>;

        PerformExpensiveOperation();
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> PerformExpensiveOperation()
    {
        <span class="rem">// Imagine that this method performs an expensive operation</span>
        <span class="rem">// that doesn't need to execute when the form loads.</span>
        MessageBox.Show(<span class="str">"Expensive operation."</span>);
    }
}</pre>

For further refinement, BeforeAndAfterBlock could be subclassed to simplify its construction and make it easier to use in multiple locations.  Also, instead of using a flag, the event handler could be detached from the event for the duration of the block and then re-attached.

    public partial class BeforeAndAfterTest : Form
    {
        public BeforeAndAfterTest()
        {
            InitializeComponent();
        }
    <span class="kwrd">protected</span> <span class="kwrd">override</span> <span class="kwrd">void</span> OnLoad(EventArgs e)
    {
        <span class="highlight"><span class="kwrd">using</span> (<span class="kwrd">new</span> LoadingBlock(<span class="kwrd">this</span>))</span>
        {
            LoadComboBoxData();

            <span class="kwrd">base</span>.OnLoad(e);
        }
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> LoadComboBoxData()
    {
        comboBox.Items.Add(<span class="str">"Item 1"</span>);
        comboBox.Items.Add(<span class="str">"Item 2"</span>);
        comboBox.Items.Add(<span class="str">"Item 3"</span>);
        comboBox.Items.Add(<span class="str">"Item 4"</span>);

        comboBox.SelectedIndex = 0;
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> comboBox_SelectedIndexChanged(
        <span class="kwrd">object</span> sender, EventArgs e)
    {
        PerformExpensiveOperation();
    }

    <span class="kwrd">private</span> <span class="kwrd">void</span> PerformExpensiveOperation()
    {
        <span class="rem">// Imagine that this method performs an expensive operation</span>
        <span class="rem">// that doesn't need to execute when the form loads.</span>
        MessageBox.Show(<span class="str">"Expensive operation."</span>);
    }

    <div class="highlight">        <span class="kwrd">private</span> <span class="kwrd">class</span> LoadingBlock : BeforeAndAfterBlock
    {
        <span class="kwrd">public</span> LoadingBlock(BeforeAndAfterTest form)
            : <span class="kwrd">base</span>(() =&gt; DetachEvents(form), () =&gt; AttachEvents(form))
        {
        }

        <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> DetachEvents(BeforeAndAfterTest form)
        {
            form.comboBox.SelectedIndexChanged -=
                form.comboBox_SelectedIndexChanged;
        }

        <span class="kwrd">private</span> <span class="kwrd">static</span> <span class="kwrd">void</span> AttachEvents(BeforeAndAfterTest form)
        {
            <span class="rem">// Detach first to prevent accidental double subscription.</span>
            form.comboBox.SelectedIndexChanged -=
                form.comboBox_SelectedIndexChanged;
            form.comboBox.SelectedIndexChanged +=
                form.comboBox_SelectedIndexChanged;
        }
    }</div>
}</pre>

Finally, I don't want to leave out my new favorite language.  Below is an implementation of the BeforeAndAfterBlock class in F# along with a simple test in the console.  Not so functional, but it works.  Perhaps there is a way to do this with computation expressions?

open System

type BeforeAndAfterBlock(fBefore, fAfter) = do fBefore()

interface IDisposable with member x.Dispose() = fAfter()

let fBefore = fun() -> printfn "Before” let fAfter = fun() -> printfn "And After”

let testBlockWithType() = use printMessageBlock = new BeforeAndAfterBlock(fBefore, fAfter) printfn "Middle”

testBlockWithType()

ignore(Console.ReadLine())

So that's it.  A pretty cool and non-standard way of using IDisposable and the using statement.

© Joe Buschmann 2020