Thread Safety in VB-2003 Events
January 15th, 2005

Brad Abrams had a recent post about how the usual way of raising an event in C#:


    protected virtual void OnMyEvent(EventArgs e)
    {
        if(MyEvent != null)
        {
            MyEvent(this, e);
        }
    }

  

is not threadsafe. Purely out of curiosity, I wondered if VB handles this the correct way:


    protected virtual void OnMyEvent(EventArgs e)
    {
        EventHandler handler = MyEvent;
        if(handler != null)
        {
            handler(this, e);
        }
    }

  

Since VB abstracts this away with the RaiseEvent keyword. Unfortunately it doesn’t seem to, as this code:


    Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
        RaiseEvent MyEvent(Me, e)
    End Sub

  

Compiles to this:


    .method family newslot virtual instance void OnMyEvent([mscorlib]System.EventArgs e) cil managed
    {
          // Code Size: 22 byte(s)
          .maxstack 8
          L_0000: ldarg.0
          L_0001: ldfld [mscorlib]System.EventHandler VbConsoleApp.Test::MyEventEvent
          L_0006: brfalse.s L_0015
          L_0008: ldarg.0
          L_0009: ldfld [mscorlib]System.EventHandler VbConsoleApp.Test::MyEventEvent
          L_000e: ldarg.0
          L_000f: ldarg.1
          L_0010: callvirt instance void [mscorlib]System.EventHandler::Invoke(object, [mscorlib]System.EventArgs)
          L_0015: ret
    }

  

Which has a race condition—it should store the delegate in a local. Generally, my answer to all of these questions is “it is fixed in 2005” — so I’m going to just assume that that is the case here.