Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

The Using Block as a Language Feature

5.00/5 (2 votes)
5 Mar 2010CPOL3 min read 1  
Download source (55.5 KB)IntroductionThe using block in C# and VB.NET can be used as a high-level language construct, not just as a way of tidying-up. In this article I show you how to capture and restore state using constructors and disposers.BackgroundIn any substantial...

Introduction



The "using" block in C# and VB.NET can be used as a high-level language construct, not just as a way of tidying-up. In this article I show you how to capture and restore state using constructors and disposers.

Background


In any substantial application, especially those with a UI, it is frequently necessary to change state to perform some task and to then restore the state after - even if an error occurs. This usually involves a Try..Catch..Finally block and a lot of boilerplate code. If the implementation of the state changes then everywhere that captures and restores the state must be changed too. Think of simple things like capturing and restoring the selection in a combo box, or changing
the cursor to an hourglass and back again. A "nicer" approach would be to have some sort of language construct that surrounds the portion of code that occurs in the alternate state. In psuedocode such a construct might look like this:
...
With(AlternateState)
{
    // Do Stuff.
}
...

The C# and VB.NET don't provide an easy way of adding language features like that, so the basis of the solution I have chosen is the "using" block (Using...End Using in VB.NET or using{...} in C#). In C# the usage is thus:
C#
using(System.IDisposable myObject = new MyDisposableType())
{
    // Do stuff.
}

This is equivalent to the following code:
C#
System.IDisposable myObject = new MyDisposableType();
try
{
    // Do stuff.
}
finally
{
    if(myObject != null)
    {
        myObject.Dispose();
    }
}

The only requirement to be able to use this construct is that the object used implements the System.IDisposable
interface. So, we have a constructor that is run at the start of the block and a Dispose method called at the end of the block. These provide the opportunity to capture and restore state respectively. If we are to fully implement the psuedocode example above then we also need to change state in the constructor, although I shan't be forcing that point.

Using the Code


In the code I provide implementations of three example cases:

ComboBoxState
  • Capture and restore the selected item in a combo box.

CursorState
  • Change and restore the cursor during an operation.

ImpersonateUser
  • Impersonate a user and restore the original user once the task is over.

The point of the three examples in the code is show how the state can be captured and changed in the constructor of the helper classes and then restored in the dispose method.

I have used all three (in rather artificial circumstances) in TestForm search for "EXAMPLE:" in the code to find them.

Points of Interest


So, what interesting points can we take from the first version of this demo code? Well, in the test form you can see a couple of simplistic methods for handling the setting of control properties from arbitrary threads - this shouldn't actually be a problem in this app. because the timer control raises events on form's main thread, but it is worth knowing about. There are probably some useful bits and pieces in the impersonation code too. This is quite old know and may contain work-arounds for bugs that no loner exists - I have included links back to the original articles to explain some of the more esoteric bits.

The main gotcha to watch out for though is unexpected changes in the state of objects prior to the dispose methods. Remember that the method may be called from an error handler or destructor and that controls or forms that have been captured in the constructor may have been disposed of themselves before you get to them. To combat this you need to code defensively and check properties such as IsHandleCreated.

History


Version 1.0
  • Initial version. It compiles and runs on my machine.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)