EventInfo.AddEventHandler(Object, Delegate) Method

Definition

Adds an event handler to an event source.

C#
public virtual void AddEventHandler(object target, Delegate handler);
C#
public virtual void AddEventHandler(object? target, Delegate? handler);
C#
public void AddEventHandler(object target, Delegate handler);

Parameters

target
Object

The event source.

handler
Delegate

Encapsulates a method or methods to be invoked when the event is raised by the target.

Implements

Exceptions

The event does not have a public add accessor.

The handler that was passed in cannot be used.

The caller does not have access permission to the member.

Note: In .NET for Windows Store apps or the Portable Class Library, catch the base class exception, MemberAccessException, instead.

The target parameter is null and the event is not static.

-or-

The EventInfo is not declared on the target.

Note: In .NET for Windows Store apps or the Portable Class Library, catch Exception instead.

Examples

The following example creates an instance of the System.Timers.Timer class, creates an event handler using a dynamic assembly, and hooks up the dynamic event handler. All actions are performed using late binding.

The Timer instance is stored in a variable of type Object, and all code that accesses the Timer does so late-bound. The example uses the Type.GetEvent method to get the Elapsed event, and the EventHandlerType property to get the delegate type for the event.

The example gets a MethodInfo for the Invoke method of the delegate type and obtains the signature of the delegate from the MethodInfo instance. The example then creates a dynamic assembly with one module containing a single type named Handler and gives the type a static method (Shared method in Visual Basic) named DynamicHandler that handles the event.

After the dynamic type is created, the example gets a MethodInfo for the finished method and uses it to create a delegate instance. This instance is passed to the AddEventHandler method to hook up the event. The program then pauses to allow the event to be raised.

C#
using System;
using System.Reflection;
using System.Reflection.Emit;

public class Example
{
    private static object? timer;

    public static void Main()
    {
        // Get the Timer type.
        Type t = typeof(System.Timers.Timer);
        // Create an instance of the Timer type.
        timer = Activator.CreateInstance(t);

        // Use reflection to get the Elapsed event.
        EventInfo? eInfo = t.GetEvent("Elapsed");

        // In order to create a method to handle the Elapsed event,
        // it is necessary to know the signature of the delegate
        // used to raise the event. Reflection.Emit can then be
        // used to construct a dynamic class with a static method
        // that has the correct signature.

        // Get the event handler type of the Elapsed event. This is
        // a delegate type, so it has an Invoke method that has
        // the same signature as the delegate. The following code
        // creates an array of Type objects that represent the
        // parameter types of the Invoke method.
        //
        Type? handlerType = eInfo?.EventHandlerType;
        MethodInfo? invokeMethod = handlerType?.GetMethod("Invoke");
        ParameterInfo[]? parms = invokeMethod?.GetParameters();
        Type[] parmTypes = new Type[parms?.Length ?? 0];
        for (int i = 0; i < parms?.Length; i++)
        {
            parmTypes[i] = parms[i].ParameterType;
        }

        // Use Reflection.Emit to create a dynamic assembly that
        // will be run but not saved. An assembly must have at
        // least one module, which in this case contains a single
        // type. The only purpose of this type is to contain the
        // event handler method. (You can use also dynamic methods,
        // which are simpler because there is no need to create an
        // assembly, module, or type.)
        //
        AssemblyName aName = new AssemblyName();
        aName.Name = "DynamicTypes";
        AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
        ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);
        TypeBuilder tb = mb.DefineType("Handler", TypeAttributes.Class | TypeAttributes.Public);

        // Create the method that will handle the event. The name
        // is not important. The method is static, because there is
        // no reason to create an instance of the dynamic type.
        //
        // The parameter types and return type of the method are
        // the same as those of the delegate's Invoke method,
        // captured earlier.
        MethodBuilder handler = tb.DefineMethod("DynamicHandler",
            MethodAttributes.Public | MethodAttributes.Static,
            invokeMethod?.ReturnType, parmTypes);

        // Generate code to handle the event. In this case, the
        // handler simply prints a text string to the console.
        //
        ILGenerator il = handler.GetILGenerator();
        il.EmitWriteLine("Timer's Elapsed event is raised.");
        il.Emit(OpCodes.Ret);

        // CreateType must be called before the Handler type can
        // be used. In order to create the delegate that will
        // handle the event, a MethodInfo from the finished type
        // is required.
        Type? finished = tb.CreateType();
        MethodInfo? eventHandler = finished?.GetMethod("DynamicHandler");

        // Use the MethodInfo to create a delegate of the correct
        // type, and call the AddEventHandler method to hook up
        // the event.
        if (handlerType is not null && eventHandler is not null)
        {
            Delegate d = Delegate.CreateDelegate(handlerType, eventHandler);
            eInfo?.AddEventHandler(timer, d);
        }

        // Late-bound calls to the Interval and Enabled property
        // are required to enable the timer with a one-second
        // interval.
        t.InvokeMember("Interval", BindingFlags.SetProperty, null, timer, new Object[] { 1000 });
        t.InvokeMember("Enabled", BindingFlags.SetProperty, null, timer, new Object[] { true });

        Console.WriteLine("Press the Enter key to end the program.");
        Console.ReadLine();
    }
}
/* This example produces output similar to the following:

Press the Enter key to end the program.
Timer's Elapsed event is raised.
Timer's Elapsed event is raised.
Timer's Elapsed event is raised.
*/

Remarks

This method attempts to add a delegate to synchronize the event on the target object.

Each time the event is raised by the target parameter, the method or methods encapsulated by the handler are invoked.

You might use the AddEventHandler method when you load a type after the program is already compiled, when it is not possible to use the C# += syntax or the Visual Basic WithEvents and Handles keywords to hook up the event.

Applies to

Product Versions
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9, 10
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0

See also