Wenn einem so viel Gutes wiederfährt...

Eigentlich handelte es sich um eine recht triviale Aufgabe...

Für meine Serie über ASP.NET Server Controls wollte ich einige Beispiele in C# und einige in VB.NET erstellen. Eines der Beispiele sollte zeigen, wie Server Controls eigene Events implementieren können und so fing der ganze Spaß an...

[ Category("Action"),

Description("Raised when the button is clicked") ]

public event EventHandler Click;

// Method of IPostBackEventHandler that raises postback events.

void IPostBackEventHandler.RaisePostBackEvent(string eventArgument){

    OnClick(EventArgs.Empty);

}

// Invokes delegate registered with the Click event.

protected virtual void OnClick(EventArgs e) {

    if (Click != null)

    {

        Click(this, e);

    }

}

Wie in dem oben stehenden Codebeispiel zu sehen ist überprüft die Methode OnClick in der ersten Zeile ob es EventHandler gibt welche dem Event („Click“) zugeordnet sind. Falls ja wird im Anschluß das Click-Event ausgeführt. Soweit so gut.

Als ich die Methode OnClick allerdings in VB.NET umsetzen wollte stellte sich mir die Frage, wie eine ähnlich Implementierung in VB.NET aussehen sollte. Nach diversen Versuchen und Diskussionen mit Kollegen zeigte ein Ausflug in die IL (Intermediate Language) dass selbige Überprüfung in VB.NET nicht nötig ist. Wie in dem nachstehenden Beispiel offensichtlich erkennbar ist erfolgt keine (explizite) Überprüfung ob EventHandler auf das Click-Event registriert wurden.

' Invokes delegate registered with the Click event.

Protected Overridable Sub OnClick(ByVal e As System.EventArgs)

    RaiseEvent Click(Me, e)

End Sub

Aufschluß gibt ein Blick in den IL-Code.

Die C# Version

.method family hidebysig newslot virtual

        instance void OnClick(class [mscorlib]System.EventArgs e) cil managed

{

  // Code size 31 (0x1f)

  .maxstack 3

  .locals init ([0] bool CS$4$0000)

  IL_0000: nop

  IL_0001: ldarg.0

  IL_0002: ldfld class [mscorlib]System.EventHandler MSPress.ServerControls.SimpleButton::Click

                       ' ldfld finds the value of a field in the object whose

                       ' reference is currently on the evaluation stack.

  IL_0007: ldnull ' Pushes a null reference (type O) onto the evaluation stack

  IL_0008: ceq ' Compares two values. If they are equal,

                       ' the integer value 1 (int32) is pushed onto

the evaluation stack;

                       ' otherwise 0 (int32) is pushed onto the evaluation stack.

  IL_000a: stloc.0 ' Pops the current value from the top of the evaluation stack and stores

                       ' it in a the  local variable list at index 0.

  IL_000b: ldloc.0 ' Loads the local variable at index 0 onto the evaluation stack.

  IL_000c: brtrue.s IL_001e ' Hier passiert’s. Wenn keine Methode auf das Delegate registriert

                               ' wurde wird die Programmausführung an IL_001e fortgesetzt.

  IL_000e: nop

  IL_000f: ldarg.0

  IL_0010: ldfld class [mscorlib]System.EventHandler MSPress.ServerControls.SimpleButton::Click

  IL_0015: ldarg.0

  IL_0016: ldarg.1

  IL_0017: callvirt instance void [mscorlib]System.EventHandler::Invoke(object,

                                          class [mscorlib]System.EventArgs)

  IL_001c: nop

  IL_001d: nop

  IL_001e: ret

} // end of method SimpleButton::OnClick

und die VB.NET Implementierung

.method family newslot strict virtual instance void

        OnClick(class [mscorlib]System.EventArgs e) cil managed

{

  // Code size 30 (0x1e)

  .maxstack 3

  .locals init ([0] class [mscorlib]System.EventHandler VB$t_ref$S0,

           [1] bool VB$CG$t_bool$S0)

  IL_0000: nop

  IL_0001: ldarg.0

  IL_0002: ldfld class [mscorlib]System.EventHandler MyControls.ServerControls.SimpleButton::ClickEvent

  IL_0007: stloc.0

  IL_0008: ldloc.0

  IL_0009: ldnull

  IL_000a: ceq

  IL_000c: ldc.i4.0 ' Pushes the integer value of 0 onto the evaluation stack as an int32.

  IL_000d: ceq

  IL_000f: stloc.1

  IL_0010: ldloc.1

  IL_0011: brfalse.s IL_001c

  IL_0013: ldloc.0

  IL_0014: ldarg.0

  IL_0015: ldarg.1

  IL_0016: callvirt instance void [mscorlib]System.EventHandler::Invoke(object,

                                    class [mscorlib]System.EventArgs)

  IL_001b: nop

  IL_001c: nop

  IL_001d: ret

} // end of method SimpleButton::OnClick

Ein Blick auf den IL-Code zeigt, dass der VB.NET Compiler im Hintergrund die Überprüfung selbst erzeugt und (fast) genau den gleichen IL Code wie in dem C# Beispiel erzeugt. Na wenn das mal nichts ist!

... und wenn einem so viel Gutes wiederfährt ist das doch einen Blog Eintrag wert :-)

Happy coding!

Daniel