11

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

Joel Coehoorn
  • 362,140
  • 107
  • 528
  • 764
Seth Spearman
  • 6,421
  • 16
  • 57
  • 102
  • PS...my point is that I DON"T want to raise the event. I actually DO want to check it for nullity because that is what I am unit testing for. Seth – Seth Spearman Jun 01 '10 at 19:28
  • I did answer the question below. However, I would also suggest that what you should be testing is that an attempt was made to register an event handler, not that it actually was registered (since that would be testing CLR functionality which is already well tested.) More specifically, consider using a [mock object](http://martinfowler.com/articles/mocksArentStubs.html) which is made easier with frameworks like [Rhino.Mocks](http://www.ayende.com/projects/rhino-mocks.aspx), [Moq](http://code.google.com/p/moq/), or [TypeMock Isolator](http://site.typemock.com/). – hemp Jun 01 '10 at 21:36

6 Answers6

11

Yes. null is called "Nothing" in Visual Basic.

If Trigger IsNot Nothing Then

Update

The above answer describes how to check something for null in VB .NET. Unfortunately, events are handled special by the VB.NET compiler.

For this event definition:

Public Event Trigger as EventHandler

You would use this code to check for subscriptions

If TriggerEvent Is Nothing

Notice how VB.Net added a field with the suffix Event to represent the delegate. Have a look here for an explanation.

JJS
  • 5,925
  • 1
  • 48
  • 68
driis
  • 151,614
  • 43
  • 262
  • 332
  • Thanks for your answer. If you look at my question you will see that Trigger IsNot Nothing causes a compile error in vb.net I forgot to mention that in my question and you answered so fast that you replied before I updated the question. Bottom line...is your code causes a compile error. Seth – Seth Spearman Jun 01 '10 at 19:32
  • 1
    @Seth Spearman: Do this instead: If TriggerEvent IsNot Nothing Then – Stefan Steiger Apr 11 '12 at 07:10
  • That's right @JJS null ain't scared of nothing, no way, no how. – kenny Jun 16 '15 at 22:55
9

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
Joel Coehoorn
  • 362,140
  • 107
  • 528
  • 764
  • 1
    Joel ... thanks for your reply. I will update my code. Please see the update to my question (This is my first C# project I am using for learning). In my case I am writing a unit test and the test is checking to verify that a handler registered for the event. But I assume from your answer there is no way to do this in vb.net. – Seth Spearman Jun 01 '10 at 19:24
9

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
Community
  • 1
  • 1
hemp
  • 5,439
  • 27
  • 40
  • hemp...thanks for your answer and your recommendation that this is better suited to mocking. I have it on my agenda to learn rhino mocks. Seth – Seth Spearman Jun 01 '10 at 22:36
  • Not awesome. It doesn't work. Event is not a field in VB.NET. This only works as VB.NET test method for C# code, in which case it is pointless anyway... But it works if you do eventName + "Event" for the field name, because the VB compiler automatically creates a field for every event. – Stefan Steiger Apr 11 '12 at 07:13
  • 1
    @Quandary the OP stated, "I have classes written in C# but I am writing my unit tests in VB.NET." Which is the problem this answer solved (and is obviously not pointless.) It would be more helpful instead to ask a new question about how to do this for VB.NET classes and answer it there accordingly instead of claiming the answer "doesn't work", since it does. – hemp Apr 12 '12 at 10:01
4

I believe the syntax I use for this in VB.Net is:

Public Event Trigger As EventHandler


Friend Sub OnTrigger(ByVal e As EventArgs)
    If TriggerEvent IsNot Nothing Then
        RaiseEvent Trigger(Me, e)
    End If
End Sub

Even though TriggerEvent does not appear to be declared the compiler will understand it.It closer emulates the C# syntax. Also I have read somehere that the code with that handler asssigned check runs fater, but I cannot point to that at the moment, so youcan take or leave that.

I think that is the sytax, anyway. Please dont shoot me if it is not quite correct!

Dibley1973
  • 41
  • 1
  • Here's an explanation of this. The VB compiler auto-generates a private hidden member for the event declaration: http://jelle.druyts.net/2003/05/09/BehindTheScenesOfEventsInVBNET.aspx – Technobabble Sep 07 '12 at 17:34
1

You should not have a unit test checking to see if a handler is registered. How would you know whether it was the correct handler, or if it was the correct handler but was behaving incorrectly?

What is the point of your test?

John Saunders
  • 157,405
  • 24
  • 229
  • 388
  • John, Thanks for your answer. It is well taken. I am working on a "learning" project and I am teaching myself both C# and unit testing on it. I guess I am taking the approach of using the unit test to define your api. So I have a method in my class under test call AddTrigger. It will add an object into that collection and at the same time register a trigger in that object. I am REALLY struggling with what to test and what not to test. I realize that there is no point to test .NET or any other external library. But then again...the setup/teardown does define only one trigger registerd. – Seth Spearman Jun 01 '10 at 19:41
  • So ... continued...I have two test methods... AddTrigger_TriggerNotExists_TriggerAdded()... AddTrigger_TriggerNotExists_EventRegistered()... Testing the first one is simple...just verifies that an item was added to teh collection. It seemed to make sure that the code..whatever it is...would verify that trigger event was registered. But maybe not. Seth – Seth Spearman Jun 01 '10 at 19:45
0

There's an interesting language "feature" in VB .NET. A member variable is created for events that exposes the delegate:

Public Event MyEvent As EventHandler
Public Sub Test()

    Dim test = MyEventEvent
    Dim invokers = test.GetInvocationList()

End Sub

You can actually get the invocation list this way.

Chris McKenzie
  • 3,203
  • 1
  • 24
  • 33