Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to know in VB.NET if a handler has been registered for an event?

In C# I can test for this...

public event EventHandler Trigger;
protected void OnTrigger(EventArgs e)
{
    if (Trigger != null)
        Trigger(this, e);
}

Is there a way to do this in VB.NET? Test for null I mean?

MORE INFO

I forgot to mention. I have classes written in C# but I am writing my unit tests in VB.NET.

I am trying this in the unit test...

If myObject.Trigger IsNot Nothing Then  
    ''#do something
End If

This is causing a compile time error which says ... "Public Event Trigger is an Event and cannot be called directly. Use the RaiseEvent statement to raise an event."

Seth

like image 990
Seth Spearman Avatar asked Jun 01 '10 19:06

Seth Spearman


2 Answers

There is an interesting discussion in question 1129517 around how to do this very thing in C#.

Since the class that contains the Event was written in C#, the delegate semantics do apply, and those techniques should work for you. However, you'll need to translate the source to VB.NET for your unit test.

Given the following class in a C# assembly:

public class Triggerific
{
    public event EventHandler Trigger;

    private static void OnTriggerTriggered(object sender, EventArgs e)
    {
        Console.WriteLine("Triggered!");
    }

    public void AddTrigger()
    {
        Trigger += OnTriggerTriggered;
    }
}

Here is some VB.NET code which will correctly determine if a handler was registered for the Trigger event:

<TestMethod()> _
Public Sub TriggerTest()
    Dim cut As New Triggerific
    cut.AddTrigger()

    Assert.IsNotNull(GetEventHandler(cut, "Trigger"))
End Sub

Private Shared Function GetEventHandler(ByVal classInstance As Object, ByVal eventName As String) As EventHandler
    Dim classType As Type = classInstance.[GetType]()
    Dim eventField As FieldInfo = classType.GetField(eventName, BindingFlags.GetField Or BindingFlags.NonPublic Or BindingFlags.Instance)

    Dim eventDelegate As EventHandler = DirectCast(eventField.GetValue(classInstance), EventHandler)

    ' eventDelegate will be null/Nothing if no listeners are attached to the event
    Return eventDelegate
End Function
like image 78
hemp Avatar answered Sep 30 '22 02:09

hemp


First of all, there's a problem with your c# code. It should read like this to reduce the likelihood of a race condition on removing the last handler in a separate thread at just the wrong time (hint on why it works: mulit-cast delegates are immutable):

public event EventHandler Trigger;
protected void OnTrigger(EventArgs e)
{
    var temp = Trigger;
    if (temp != null)
        temp(this, e);
}

Secondly, there's no need for this code at all in VB.Net. VB handles events a little differently, such that you should not check at all whether any handlers are registered. It's safe and preferred to just raise the event:

Public Event Trigger As EventHandler
Friend Sub OnTrigger(ByVal e As EventArgs)
    RaiseEvent Trigger(Me, e)
End Sub
like image 41
Joel Coehoorn Avatar answered Sep 30 '22 03:09

Joel Coehoorn