How to: Hook Up a Delegate Using Reflection

When you use reflection to load and run assemblies, you cannot use language features like the C# += operator or the Visual Basic AddHandler statement to hook up events. The following procedures show how to hook up an existing method to an event by getting all the necessary types through reflection, and how to create a dynamic method using reflection emit and hook it up to an event.

Note Note

For another way to hook up an event-handling delegate, see the code example for the AddEventHandler method of the EventInfo class.

To hook up a delegate using reflection

  1. Load an assembly that contains a type that raises events. Assemblies are usually loaded with the Assembly.Load method. To keep this example simple, a derived form in the current assembly is used, so the GetExecutingAssembly method is used to load the current assembly.

    Dim assem As Assembly = GetType(Example).Assembly
    
  2. Get a Type object representing the type, and create an instance of the type. The CreateInstance(Type) method is used in the following code because the form has a default constructor. There are several other overloads of the CreateInstance method that you can use if the type you are creating does not have a default constructor. The new instance is stored as type Object to maintain the fiction that nothing is known about the assembly. (Reflection allows you to get the types in an assembly without knowing their names in advance.)

    Dim tExForm As Type = assem.GetType("ExampleForm")
    Dim exFormAsObj As Object = _
        Activator.CreateInstance(tExForm)
    
  3. Get an EventInfo object representing the event, and use the EventHandlerType property to get the type of delegate used to handle the event. In the following code, an EventInfo for the Click event is obtained.

    Dim evClick As EventInfo = tExForm.GetEvent("Click")
    Dim tDelegate As Type = evClick.EventHandlerType
    
  4. Get a MethodInfo object representing the method that handles the event. The complete program code in the Example section later in this topic contains a method that matches the signature of the EventHandler delegate, which handles the Click event, but you can also generate dynamic methods at run time. For details, see the accompanying procedure, for generating an event handler at run time by using a dynamic method.

    Dim miHandler As MethodInfo = _
        GetType(Example).GetMethod("LuckyHandler", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
    
  5. Create an instance of the delegate, using the CreateDelegate method. This method is static (Shared in Visual Basic), so the delegate type must be supplied. Using the overloads of CreateDelegate that take a MethodInfo is recommended.

    Dim d As [Delegate] = _
        [Delegate].CreateDelegate(tDelegate, Me, miHandler)
    
  6. Get the add accessor method and invoke it to hook up the event. All events have an add accessor and a remove accessor, which are hidden by the syntax of high-level languages. For example, C# uses the += operator to hook up events, and Visual Basic uses the AddHandler statement. The following code gets the add accessor of the Click event and invokes it late-bound, passing in the delegate instance. The arguments must be passed as an array.

    Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
    Dim addHandlerArgs() As Object = { d }
    miAddHandler.Invoke(exFormAsObj, addHandlerArgs)
    
  7. Test the event. The following code shows the form defined in the code example. Clicking the form invokes the event handler.

    Application.Run(CType(exFormAsObj, Form))
    

To generate an event handler at run time by using a dynamic method

  1. Event-handler methods can be generated at run time, using lightweight dynamic methods and reflection emit. To construct an event handler, you need the return type and parameter types of the delegate. These can be obtained by examining the delegate's Invoke method. The following code uses the GetDelegateReturnType and GetDelegateParameterTypes methods to obtain this information. The code for these methods can be found in the Example section later in this topic.

    It is not necessary to name a DynamicMethod, so the empty string can be used. In the following code, the last argument associates the dynamic method with the current type, giving the delegate access to all the public and private members of the Example class.

    Dim returnType As Type = GetDelegateReturnType(tDelegate)
    If returnType IsNot GetType(Void) Then 
        Throw New ApplicationException("Delegate has a return type.")
    End If 
    
    Dim handler As New DynamicMethod( _
        "", _
        Nothing, _
        GetDelegateParameterTypes(tDelegate), _
        GetType(Example) _
    )
    
  2. Generate a method body. This method loads a string, calls the overload of the MessageBox.Show method that takes a string, pops the return value off the stack (because the handler has no return type), and returns. To learn more about emitting dynamic methods, see How to: Define and Execute Dynamic Methods.

    Dim ilgen As ILGenerator = handler.GetILGenerator()
    
    Dim showParameters As Type() = { GetType(String) }
    Dim simpleShow As MethodInfo = _
        GetType(MessageBox).GetMethod("Show", showParameters)
    
    ilgen.Emit(OpCodes.Ldstr, _
        "This event handler was constructed at run time.")
    ilgen.Emit(OpCodes.Call, simpleShow)
    ilgen.Emit(OpCodes.Pop)
    ilgen.Emit(OpCodes.Ret)
    
  3. Complete the dynamic method by calling its CreateDelegate method. Use the add accessor to add the delegate to the invocation list for the event.

    Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
    miAddHandler.Invoke(exFormAsObj, New Object() { dEmitted })
    
  4. Test the event. The following code loads the form defined in the code example. Clicking the form invokes both the predefined event handler and the emitted event handler.

    Application.Run(CType(exFormAsObj, Form))
    

The following code example shows how to hook up an existing method to an event using reflection, and also how to use the DynamicMethod class to emit a method at run time and hook it up to an event.

Imports System.Reflection
Imports System.Reflection.Emit
Imports System.Windows.Forms

Class ExampleForm
    Inherits Form

    Public Sub New() 
        Me.Text = "Click me" 

    End Sub 'New 
End Class 'ExampleForm

Class Example
    Public Shared Sub Main() 
        Dim ex As New Example()
        ex.HookUpDelegate()
    End Sub 'Main

    Private Sub HookUpDelegate() 
        ' Load an assembly, for example using the Assembly.Load 
        ' method. In this case, the executing assembly is loaded, to 
        ' keep the demonstration simple. 
        
        Dim assem As Assembly = GetType(Example).Assembly

        ' Get the type that is to be loaded, and create an instance  
        ' of it. Activator.CreateInstance also has an overload that 
        ' takes an array of types representing the types of the  
        ' constructor parameters, if the type you are creating does 
        ' not have a parameterless constructor. The new instance 
        ' is stored as type Object, to maintain the fiction that  
        ' nothing is known about the assembly. (Note that you can 
        ' get the types in an assembly without knowing their names 
        ' in advance.) 
        
        Dim tExForm As Type = assem.GetType("ExampleForm")
        Dim exFormAsObj As Object = _
            Activator.CreateInstance(tExForm)

        ' Get an EventInfo representing the Click event, and get the 
        ' type of delegate that handles the event. 
        
        Dim evClick As EventInfo = tExForm.GetEvent("Click")
        Dim tDelegate As Type = evClick.EventHandlerType

        ' If you already have a method with the correct signature, 
        ' you can simply get a MethodInfo for it.  
        
        Dim miHandler As MethodInfo = _
            GetType(Example).GetMethod("LuckyHandler", _
                BindingFlags.NonPublic Or BindingFlags.Instance)
        ' Create an instance of the delegate. Using the overloads 
        ' of CreateDelegate that take MethodInfo is recommended. 
        
        Dim d As [Delegate] = _
            [Delegate].CreateDelegate(tDelegate, Me, miHandler)

        ' Get the "add" accessor of the event and invoke it late- 
        ' bound, passing in the delegate instance. This is equivalent 
        ' to using the += operator in C#, or AddHandler in Visual 
        ' Basic. The instance on which the "add" accessor is invoked 
        ' is the form; the arguments must be passed as an array. 
        
        Dim miAddHandler As MethodInfo = evClick.GetAddMethod()
        Dim addHandlerArgs() As Object = { d }
        miAddHandler.Invoke(exFormAsObj, addHandlerArgs)

        ' Event handler methods can also be generated at run time, 
        ' using lightweight dynamic methods and Reflection.Emit.  
        ' To construct an event handler, you need the return type 
        ' and parameter types of the delegate. These can be obtained 
        ' by examining the delegate's Invoke method.  
        
        ' It is not necessary to name dynamic methods, so the empty  
        ' string can be used. The last argument associates the  
        ' dynamic method with the current type, giving the delegate 
        ' access to all the public and private members of Example, 
        ' as if it were an instance method. 
        
        Dim returnType As Type = GetDelegateReturnType(tDelegate)
        If returnType IsNot GetType(Void) Then 
            Throw New ApplicationException("Delegate has a return type.")
        End If 

        Dim handler As New DynamicMethod( _
            "", _
            Nothing, _
            GetDelegateParameterTypes(tDelegate), _
            GetType(Example) _
        )

        ' Generate a method body. This method loads a string, calls  
        ' the Show method overload that takes a string, pops the  
        ' return value off the stack (because the handler has no 
        ' return type), and returns. 
        
        Dim ilgen As ILGenerator = handler.GetILGenerator()

        Dim showParameters As Type() = { GetType(String) }
        Dim simpleShow As MethodInfo = _
            GetType(MessageBox).GetMethod("Show", showParameters)

        ilgen.Emit(OpCodes.Ldstr, _
            "This event handler was constructed at run time.")
        ilgen.Emit(OpCodes.Call, simpleShow)
        ilgen.Emit(OpCodes.Pop)
        ilgen.Emit(OpCodes.Ret)

        ' Complete the dynamic method by calling its CreateDelegate 
        ' method. Use the "add" accessor to add the delegate to 
        ' the invocation list for the event. 
        
        Dim dEmitted As [Delegate] = handler.CreateDelegate(tDelegate)
        miAddHandler.Invoke(exFormAsObj, New Object() { dEmitted })

        ' Show the form. Clicking on the form causes the two 
        ' delegates to be invoked. 
        '
        Application.Run(CType(exFormAsObj, Form))

    End Sub 

    Private Sub LuckyHandler(ByVal sender As [Object], _
        ByVal e As EventArgs) 

        MessageBox.Show("This event handler just happened to be lying around.")
    End Sub 

    Private Function GetDelegateParameterTypes(ByVal d As Type) _
        As Type() 

        If d.BaseType IsNot GetType(MulticastDelegate) Then 
            Throw New ApplicationException("Not a delegate.")
        End If 

        Dim invoke As MethodInfo = d.GetMethod("Invoke")
        If invoke Is Nothing Then 
            Throw New ApplicationException("Not a delegate.")
        End If 

        Dim parameters As ParameterInfo() = invoke.GetParameters()
        ' Dimension this array Length - 1, because VB adds an extra 
        ' element to zero-based arrays. 
        Dim typeParameters(parameters.Length - 1) As Type
        For i As Integer = 0 To parameters.Length - 1
            typeParameters(i) = parameters(i).ParameterType
        Next i

        Return typeParameters

    End Function  


    Private Function GetDelegateReturnType(ByVal d As Type) As Type 

        If d.BaseType IsNot GetType(MulticastDelegate) Then 
            Throw New ApplicationException("Not a delegate.")
        End If 

        Dim invoke As MethodInfo = d.GetMethod("Invoke")
        If invoke Is Nothing Then 
            Throw New ApplicationException("Not a delegate.")
        End If 

        Return invoke.ReturnType

    End Function  
End Class

  • The code contains the C# using statements (Imports in Visual Basic) necessary for compilation.

  • No additional assembly references are required for compiling from the command line. In Visual Studio you must add a reference to System.Windows.Forms.dll because this example is a console application.

  • Compile the code at the command line using csc.exe, vbc.exe, or cl.exe. To compile the code in Visual Studio, place it in a console application project template.

Was this page helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2015 Microsoft