EventsHelper using Fire and Forget

By Fons Sonnemans, 7-3-2004

I have used the EventsHelper class to fire events asynchronical. I came across this class in the TechEd 2003 presentation C# Best Practices from Eric Gunnerson and Juval Löwy. Today I noticed a bug. The FireAsync() method uses the 'Fire and Forget' pattern incorrectly.

The 'Fire and Forget' pattern is used when the return value and returned parameters of the call are not required, and when there is no need to synchronize with the asynchronously executing method. In this case, the caller simply needs to call BeginInvoke, passing any normal and ref parameters, and null for the callback and asyncState.

This has been a commonly used pattern. However, there has been a documentation change in version 1.1 of the .NET Framework that has big ramifications for this technique of making async calls. The documentation now states that EndInvoke must be called for a corresponding BeginInvoke--otherwise Microsoft say they may now, or in the future, leak resources. It appears that no resources are leaked under version 1.0 of the framework; however, with this type of warning in place, it is recommended that a call to EndInvoke be made even if the return values of an async call are not required.

It is relatively straightforward to create a helper class that handles this for you--one example I found here.

public class AsyncHelper {

    delegate void DynamicInvokeShimProc(Delegate d, object[] args);

    static DynamicInvokeShimProc dynamicInvokeShim = new
        DynamicInvokeShimProc(DynamicInvokeShim);

    static AsyncCallback dynamicInvokeDone = new
        AsyncCallback(DynamicInvokeDone);

    public static void FireAndForget(Delegate d, params object[] args) {
        dynamicInvokeShim.BeginInvoke(d, args, dynamicInvokeDone, null);
    }

    static void DynamicInvokeShim(Delegate d, object[] args) {
        d.DynamicInvoke(args);
    }

    static void DynamicInvokeDone(IAsyncResult ar) {
        dynamicInvokeShim.EndInvoke(ar);
    }
}

My improved EventsHelper class now looks like this:

public class EventsHelper {

    public static void FireAsync(Delegate del, params object[] args) {
        if (del == null) {
            return;
        }
        Delegate[] delegates = del.GetInvocationList();
        AsyncFire asyncFire;
        foreach (Delegate sink in delegates) {
            asyncFire = new AsyncFire(InvokeDelegate);
            AsyncHelper.FireAndForget(asyncFire, sink, args);
        }
    }

    delegate void AsyncFire(Delegate del, object[] args);

    [OneWay]
    static void InvokeDelegate(Delegate del, object[] args) {
        del.DynamicInvoke(args);
    }

    public static void Fire(Delegate del, params object[] args) {
        if (del == null) {
            return;
        }
        Delegate[] delegates = del.GetInvocationList();
        foreach (Delegate sink in delegates) {
            try {
                sink.DynamicInvoke(args);
            }
            catch {}
        }
    }
}

Leave a Comment

Leave a Comment
Name
Comment
4 + 1 =

0 Comments

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.