« July 2008 | Main | September 2008 »

August 25, 2008

Event subscription using weak references

In my previous post, I never really explained why it can be important to unsubscribe from events.

It is often the case that the "subject" (the object with the event) has a longer lifetime than the "observer" (the object that subscribes to the event). When we are no longer using the observer, we would like it to be garbage collected; however, if the observer is still subscribed to an event on the subject, the associated event handler holds a strong reference to the observer, so the observer will not be garbage collected until the subject also becomes garbage, or until the observer unsubscribes.

However, it is sometimes impossible (or very inconvenient) to determine the lifetime of an object, and so it isn't possible to know when it would be safe to unsubscribe from the event. In that case, it would be really nice if we could subscribe to the event with a “weak delegate” – an event handler that would allow the target to be garbage collected.

Greg Schechter has the best article that I could find on this subject, and I encourage you to read it for more information. (His “containee” is our “subject” and his “container” is our “observer”.)

By using the EventInfo class from the previous post, we have created a method that allows a “weak subscription” to any event. Here's an example, similar to the examples from that post.

public sealed class Observer

{

    public Observer(Subject subject)

    {

        Subject.NotifyEvent.WeakSubscribe(subject, this,

            (t, s, e) => t.UpdateSubject(subject));

    }

 

    private void UpdateSubject(Subject subject)

    {

        // ...

    }

}

Note that the Observer class is not disposable. Also note that the delegate passed to WeakSubscribe does not hold a strong reference to the Observer. The WeakSubscribe method is passed a strong reference to the Observer via “this”, but it only ends up holding a weak reference to that reference.

For reasons that will (hopefully) become clear, we define WeakSubscribe as an extension method; in this form, it only works with events that use the simple EventHandler delegate:

public static Scope WeakSubscribe<TSource, TTarget>(

    this EventInfo<TSource, EventHandler> info,

    TSource source, TTarget target, Action<TTarget, object, EventArgs> action)

        where TTarget : class

{

    WeakReference weakTarget = new WeakReference(target, false);

 

    EventHandler handler = null;

    handler =

        (s, e) =>

        {

            TTarget t = (TTarget) weakTarget.Target;

            if (t != null)

                action(t, s, e);

            else

                info.RemoveHandler(source, handler);

        };

    return info.Subscribe(source, handler);

}

Note how the actual event handler only calls the supplied delegate if the weak reference to the target is still valid. If it is not, the handler is removed, since it is no longer necessary.

This method also returns a Scope that unsubscribes from the event, for cases where the client wants to unsubscribe before the target is garbage collected.

We can support WeakSubscribe on events that use EventHandler<T> with just a few minor changes:

public static Scope WeakSubscribe<TSource, TTarget, TEventArgs>(

    this EventInfo<TSource, EventHandler<TEventArgs>> info,

    TSource source, TTarget target,

    Action<TTarget, object, TEventArgs> action)

        where TTarget : class

        where TEventArgs : EventArgs

{

    WeakReference weakTarget = new WeakReference(target, false);

 

    EventHandler<TEventArgs> handler = null;

    handler =

        (s, e) =>

        {

            TTarget t = (TTarget) weakTarget.Target;

            if (t != null)

                action(t, s, e);

            else

                info.RemoveHandler(source, handler);

        };

    return info.Subscribe(source, handler);

}

Finally, we can support WeakSubscribe on events that use any standard event handler (e.g. CancelEventHandler) by using DelegateUtility.Cast:

public static Scope WeakSubscribe<TSource, TTarget, TEventArgs, TEventHandler>(

    this EventInfo<TSource, TEventHandler> info,

    TSource source, TTarget target,

    Action<TTarget, object, TEventArgs> action)

        where TTarget : class

        where TEventHandler : class

        where TEventArgs : EventArgs

{

    WeakReference weakTarget = new WeakReference(target, false);

 

    TEventHandler handler = null;

    Action<object, TEventArgs> fn =

        (arg1, arg2) =>

        {

            TTarget t = (TTarget) weakTarget.Target;

            if (t != null)

                action(t, arg1, arg2);

            else

                info.RemoveHandler(source, handler);

        };

    handler = DelegateUtility.Cast<TEventHandler>(fn);

    return info.Subscribe(source, handler);

}

All told, these methods make it very easy to “weakly” subscribe to events from any source. We welcome any comments, questions, or criticisms, as always!

Posted by Ed Ball at 9:32 AM | TrackBack

August 21, 2008

Unsubscribing from C# events

Unsubscribing from C# events can be a pain. It isn't so bad when your event handler is a simple static or instance method, because those methods are still available when you're ready to unsubscribe.

public sealed class Subject

{

    public event EventHandler Notify;

 

    // ...

}

 

public sealed class Observer : IDisposable

{

    public Observer(Subject subject)

    {

        m_subject = subject;

        m_subject.Notify += Subject_Notify;

    }

 

    public void Dispose()

    {

        m_subject.Notify -= Subject_Notify;

    }

 

    private void Subject_Notify(object sender, EventArgs e)

    {

        // ...

    }

 

    readonly Subject m_subject;

}

When you subscribe to an event using an anonymous delegate, however, things get trickier. You've got to keep that delegate around so that you can remove it from the event.

public sealed class Observer : IDisposable

{

    public Observer(Subject subject)

    {

        m_subject = subject;

        m_handler = delegate { UpdateSubject(); };

        m_subject.Notify += m_handler;

    }

 

    public void Dispose()

    {

        m_subject.Notify -= m_handler;

    }

 

    private void UpdateSubject()

    {

        // ...

    }

 

    readonly Subject m_subject;

    readonly EventHandler m_handler;

}

The Scope class can be a convenient way to encapsulate the lifetime of an event, though it is a bit awkward, because you have to declare a local variable for the event handler.

public sealed class Observer : IDisposable

{

    public Observer(Subject subject)

    {

        EventHandler handler = delegate { UpdateSubject(subject); };

        subject.Notify += handler;

        m_scope = Scope.Create(() => subject.Notify -= handler);

    }

 

    public void Dispose()

    {

        m_scope.Dispose();

    }

 

    private void UpdateSubject(Subject subject)

    {

        // ...

    }

 

    readonly Scope m_scope;

}

We've written an EventInfo class that encapsulates the add/remove behavior of any event and makes it easy to create a Scope that unsubscribes to an event.

public sealed class EventInfo<TSource, TEventHandler>

{

    public EventInfo(Action<TSource, TEventHandler> fnAddHandler,

        Action<TSource, TEventHandler> fnRemoveHandler)

    {

        m_fnAddHandler = fnAddHandler;

        m_fnRemoveHandler = fnRemoveHandler;

    }

 

    public void AddHandler(TSource source, TEventHandler handler)

    {

        m_fnAddHandler(source, handler);

    }

 

    public void RemoveHandler(TSource source, TEventHandler handler)

    {

        m_fnRemoveHandler(source, handler);

    }

 

    public Scope Subscribe(TSource source, TEventHandler handler)

    {

        AddHandler(source, handler);

        return Scope.Create(() => RemoveHandler(source, handler));

    }

 

    readonly Action<TSource, TEventHandler> m_fnAddHandler;

    readonly Action<TSource, TEventHandler> m_fnRemoveHandler;

}

Here's how EventInfo would be used:

public sealed class Subject

{

    public event EventHandler Notify;

 

    public static readonly EventInfo<Subject, EventHandler> NotifyEvent =

        new EventInfo<Subject, EventHandler>(

            (s, eh) => s.Notify += eh, (s, eh) => s.Notify -= eh);

 

    // ...

}

 

public sealed class Observer : IDisposable

{

    public Observer(Subject subject)

    {

        m_scope = Subject.NotifyEvent.Subscribe(subject,

            delegate { UpdateSubject(subject); });

    }

 

    public void Dispose()

    {

        m_scope.Dispose();

    }

 

    private void UpdateSubject(Subject subject)

    {

        // ...

    }

 

    readonly Scope m_scope;

}

Any class with events can expose static read-only EventInfo fields to help clients with this pattern, but a client is certainly capable of creating EventInfo instances on its own, since the EventInfo doesn't manage the process of raising the event at all.

If you're using the Subscribe pattern a lot with a single event, the EventInfo class is probably worth using. However, the real reason we created EventInfo was to make it easier to subscribe to events with weak references, which will be the subject of my next post.

Posted by Ed Ball at 10:18 AM | TrackBack

August 20, 2008

Leverage using blocks with Scope

Making sure that cleanup code is called even in the face of an exception is usually the job of try-finally blocks.

public class Command

{

    // ...

 

    public void Execute()

    {

        try

        {

            IsWorking = true;

            ExecuteCore();

        }

        finally

        {

            IsWorking = false;

        }

    }

}

The standard way to provide cleanup code for a class is to implement IDisposable, which provides a Dispose method that does the cleanup. Since writing try-finally blocks properly is a pain, the using statement in C# makes this much easier. But what about cleanup code that isn't in a Dispose method? Can the using statement help us with that? Of course; all you need is a specialized type that implements IDisposable. For efficiency, you can even use a struct.

public void Execute()

{

    using (new IsWorkingScope(this))

    {

        IsWorking = true;

        ExecuteCore();

    }

}

 

private struct IsWorkingScope : IDisposable

{

    public IsWorkingScope(Command command)

    {

        m_command = command;

    }

 

    public void Dispose()

    {

        m_command.IsWorking = false;

    }

 

    readonly Command m_command;

}

Of course, defining a specialized type isn't very convenient. Sometimes you want to define your cleanup code as a lambda or an anonymous delegate. For this, we use the Scope class.

public void Execute()

{

    using (Scope.Create(() => IsWorking = false))

    {

        IsWorking = true;

        ExecuteCore();

    }

}

The implementation of Scope is very straightforward; the following is the minimal implementation that we started with. We decided to use a static Create method because we thought it looked better than using a constructor.

public sealed class Scope : IDisposable

{

    public static Scope Create(Action fnDispose)

    {

        return new Scope(fnDispose);

    }

 

    public void Dispose()

    {

        if (m_fnDispose != null)

        {

            m_fnDispose();

            m_fnDispose = null;

        }

    }

 

    private Scope(Action fnDispose)

    {

        m_fnDispose = fnDispose;

    }

 

    Action m_fnDispose;

}

We added a Cancel method when we realized that it is sometimes useful to conditionally not execute the cleanup code.

public void Cancel()

{

    m_fnDispose = null;

}

The Transfer method is a useful way of returning a Scope that would otherwise be disposed by an enclosed using block.

public Scope Transfer()

{

    Scope scope = new Scope(m_fnDispose);

    m_fnDispose = null;

    return scope;

}

Finally, the Empty static field makes it easy to return a Scope that does nothing when disposed.

public static readonly Scope Empty = new Scope(null);

There are those that would consider Scope to be a misuse of the dispose pattern, but we have found it extremely useful.

Posted by Ed Ball at 9:52 AM | TrackBack

August 19, 2008

Image Format Error when Loading from a Stream

The Microsoft Windows Imaging Component (WIC) is “an extensible framework for encoding, decoding, and manipulating images”. It's also the core of WPF’s System.Windows.Media.Imaging classes; this meant that a curious exception I got when using BitmapSource eventually led me to discover a possible bug in IWICImagingFactory::CreateDecoderFromStream.

My code was loading a large number of images from disk. The files contained a header with some image metadata, followed immediately by a regular Windows bitmap (in the ubiquitous BMP file format). The code would read the header from the stream, then load the bitmap from the rest of the stream, as follows:

using (Stream stream = new FileStream(filename, FileMode.Open))

{

    // read header

    stream.Read(header, 0, header.Length);

    // etc.

 

    BitmapImage bitmap = new BitmapImage();

    bitmap.BeginInit();

    bitmap.CacheOption = BitmapCacheOption.OnLoad;

    bitmap.StreamSource = stream;

    bitmap.EndInit();

    return bitmap;

}

Some images would fail to load, with EndInit throwing a mysterious System.IO.FileFormatException: “The image format is unrecognized”. The InnerException was System.Runtime.InteropServices.COMException (0x88982F07), with an HRESULT of a WIC error code: WINCODEC_ERR_UNKNOWNIMAGEFORMAT.

My first thought was that the images were somehow corrupted, but further investigation showed that the files loaded without errors if the header preceding the bitmap was removed from the file, or if the bitmap data following the header was first copied to a new MemoryStream before being loaded. I observed the same behaviour with IWICImagingFactory::CreateDecoderFromStream when I rewrote the test harness as a C++ COM application: if the IStream containing the image contained any data preceding the bitmap data, an error HRESULT would sometimes be returned.

It appears that, in certain circumstances, CreateDecoderFromStream assumes that the bitmap data begins at the stream's origin, and absolute offsets within the stream are used when seeking; thus, the image data must begin at offset 0 within the stream. As a workaround, you can copy the image data to a new MemoryStream (but note that this may increase memory usage). The solution I chose was to write a thin Stream wrapper class that handles calls to Position, Seek, Length, etc. and adjusts the offsets so that the image now appears to start at offset 0; all other calls are passed straight through to the underlying FileStream. This allows WIC and WPF to load all the images without having to make an unnecessary copy of the bitmap, or having to change the legacy file format.

Posted by Bradley Grainger at 6:33 PM | TrackBack

August 15, 2008

Fix for error C2373 after upgrading to VS2008 SP1

After upgrading to Visual Studio 2008 Service Pack 1, you may receive the following error when compiling C++ code:

C:\Program Files\VStudio9\VC\include\intrin.h(204) : error C2373: '_InterlockedCompareExchange' : redefinition; different type modifiers
        C:\Program Files\VStudio9\VC\include\memory(995) : see declaration of '_InterlockedCompareExchange'

This bug was first noted in the comments to the release notes for the Visual C++ 2008 Feature Pack. The Visual C++ team added a workaround in the final release of VC9 SP1; this workaround is buried (as point #13) in the TR1 fixes post.

To fix the problem, define the symbol _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY for the affected project. I found that it was easiest to do this by adding these two lines to StdAfx.h:

#define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY

#include <intrin.h>

Posted by Bradley Grainger at 4:55 PM | TrackBack