3

I realise there are a number of questions out there which deal with raising an event via reflection, however I haven't been able to find an answer to the following [I suspect the answer is "no"]:

Given a "standard" declaration of an event, is there any way to raise the event by reference to a string literal.

For example, pseudocode:

Dim eventName As String = "TestEvent"
RaiseEvent eventName

Obviously that won't work.

I can get the type of the event handler / multicast delegate with

Me.GetType.GetEvent("TestEvent").GetAddMethod.GetParameters(0).Name
// "TestEventEventHandler

But I can't find the instance of this on the page object to call .GetInvocationList

This is similar to this question: How can I get an actual EventHandler delegate instance from an event in VB.NET?

However here I'm specifically looking at raising an event from a string.

Edit:

A couple of things are different in the vb.net / webforms environment. As per my comment to the accepted answer, due to (I believe) the nature of the code-behind model, it's not possible to return the field corresponding to the event from Me.GetType(), as during runtime Me refers to the inheriting class in the .aspx file rather than the class in the .aspx.vb file.

In effect this means I have to use Me.BaseType.GetType() to find the field.

The second thing which is different, though not related to the final answer, is that while in c# you can directly refer to the event handler MulticastDelegate, in vb.net you can't - or at least, to do so you have to use an undocumented feature unsupported by intellisense, as per: How can I get an actual EventHandler delegate instance from an event in VB.NET?

Community
  • 1
  • 1
mrmillsy
  • 495
  • 3
  • 14
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Dec 17 '14 at 17:33
  • Ok thanks. I have a question here though - this is specifically a vb.net/asp.net question, as the solutions for c#/winforms are different to the solutions for vb.net/webforms. Should I reflect this necessary element of the question in the title or only in the question? I feel it's misleading to suggest that the question is a generic ".net events via reflection" question. – mrmillsy Dec 18 '14 at 09:21
  • For now I've edited the question to reflect the difficulties posed by webforms/vb.net – mrmillsy Dec 18 '14 at 09:21
  • From having re-read the thread you linked to, I've updated the title. Do you think this is more appropriate? – mrmillsy Dec 18 '14 at 09:40
  • Much better. You have turned metadata into data. – John Saunders Dec 18 '14 at 15:35

2 Answers2

1

You can call GetField on your type instance and then proceed to call GetValue() on the FieldInfo returned. Here's an example (in c# because I don't speak vb.net)

class Foo
{
    public event EventHandler Bar;

}
class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo();
        foo.Bar += FooOnBar;

        var ev = (MulticastDelegate)foo.GetType().GetField("Bar", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(foo);
        if (ev != null)
        {
            foreach (var del in ev.GetInvocationList())
            {
                del.Method.Invoke(del.Target, new object[] {foo, new EventArgs()});
            }
        }
        Console.ReadLine();
    }

    private static void FooOnBar(object sender, EventArgs eventArgs)
    {
        Console.WriteLine("Invoked!");
    }
}
Tejas Sharma
  • 3,420
  • 22
  • 35
  • Thanks, this is ostensibly the answer, so I'll upvote it, however I don't think it accurately takes into account the webforms concept, which is what makes this question distinct from other similar answers, such as http://stackoverflow.com/questions/198543/how-do-i-raise-an-event-via-reflection-in-net-c. For this reason I'll withhold the tick. – mrmillsy Dec 18 '14 at 09:30
0

The problem I was having was that iterating through the field collection of Me.GetType() wasn't returning the "TestEvent" field. I did some further digging and realised that that is because the event is declared in the "code behind" class, e.g. myPageName.aspx.vb, however, during runtime, this code was being called from the inheriting "design" class, e.g. myPageName.aspx.

This blog post pointed out that even with BindingFlags.FlattenHierarchy, .GetType.GetField() will not return private static fields from inherited classes: https://web.archive.org/web/20131213074318/http://bobpowell.net/eventsubscribers.aspx

As a result, the solution was to use Me.GetType.BaseType.GetField("TestEvent"), and from there use the technique as described by Tejas Sharma. A VB.NET example of this technique is offered in this answer: How to Attach the Events of an Original Object to a Deep Copied Clone

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
mrmillsy
  • 495
  • 3
  • 14