Question

I have the following code in one assembly:

namespace MyLibrary
{
    class InternalClass
    {
        public event EventHandler<MyArgs> MyEvent;

        public void RaiseMyEvent()
        {
            MyEvent(this, new MyArgs());
        }
    }

    class MyArgs : EventArgs
    {
    }
}

and the following code in another assembly:

namespace MyApp
{
    class Program
    {
        static void Main()
        {
            var assembly = Assembly.LoadFrom(@"C:\path\to\MyLibrary.dll");
            var types = assembly.GetTypes();
            var internalClassType = types.FirstOrDefault(t => t.FullName == "MyLibrary.InternalClass");
            var eventInfo = internalClassType.GetEvent("MyEvent");

            var internalClass = Activator.CreateInstance(internalClassType);
            eventInfo.AddEventHandler(internalClass,
                Delegate.CreateDelegate(eventInfo.EventHandlerType, typeof(Program), "MyHandler"));

            internalClassType.GetMethod("RaiseMyEvent").Invoke(internalClass, new object[0]);
        }

        public static void MyHandler(object sender, EventArgs e)
        {
        }
    }
}

However, I get the following exception at Delegate.CreateDelegate: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

The types in the first assembly are internal and cannot be changed, nor grant friend assembly access to the second.

I tried to dynamically create a method via the following:

namespace MyApp
{
    class Program
    {
        static void Main()
        {
            var assembly = Assembly.LoadFrom(@"C:\path\to\MyLibrary.dll");
            var types = assembly.GetTypes();
            var internalClassType = types.FirstOrDefault(t => t.FullName == "MyLibrary.InternalClass");
            var myArgsType = types.FirstOrDefault(t => t.FullName == "MyLibrary.MyArgs");
            var eventInfo = internalClassType.GetEvent("MyEvent");

            var methodInfo = typeof(Program).GetMethod("MyHandler");
            var method = new DynamicMethod("MyHandlerImpl", null, new[] { typeof(object), myArgsType });
            var generator = method.GetILGenerator();
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Call, methodInfo);
            generator.Emit(OpCodes.Ret);

            var internalClass = Activator.CreateInstance(internalClassType);
            eventInfo.AddEventHandler(internalClass, method.CreateDelegate(eventInfo.EventHandlerType));

            internalClassType.GetMethod("RaiseMyEvent").Invoke(internalClass, new object[0]);
        }

        public static void MyHandler(object sender, EventArgs e)
        {
        }
    }
}

However, I get the following exception at MethodBase.Invoke: Attempt by method 'DynamicClass.MyHandlerImpl(System.Object, MyLibrary.MyArgs)' to access type 'MyLibrary.MyArgs' failed.

Is there any way I can handle an event when I do not have access to the EventArgs type?

Was it helpful?

Solution

Actually, I figured it out.

I changed

var method = new DynamicMethod("MyHandlerImpl", null, new[] { typeof(object), myArgsType });

to

var method = new DynamicMethod("MyHandlerImpl", null, new[] { typeof(object), typeof(EventArgs) });

and made the Program class public and everything worked.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top