如何使用反射在 C# 中发出和调用事件?



我正在尝试在运行时使用反射创建一个事件,并尝试在操作之前调用它。类似 INotifyPropertyChanged。但我无法调用我的事件。我希望它调用subscibed方法,在本例中为Boss1.HeardIt((并将"I Heard you buddy"打印到屏幕上。我做错了什么,我怎么能做?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
namespace StackOverflowSoru
{
public delegate void SomeththingHappenedEventHandler();
public interface Iperson
{
void Work(string message);
event SomeththingHappenedEventHandler SomeththingHappened;
}
public class person : Iperson
{
public event SomeththingHappenedEventHandler SomeththingHappened;
public void Work(string thework)
{
Console.WriteLine("Working on: {0}", thework);
}
}
class Boss
{
public void HeardIt()
{
Console.WriteLine("I Heard you buddy");
}
}
class Program
{
static Type CreateDynamicProxyType()
{
var assemblyName = new AssemblyName("MyProxies");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName,
AssemblyBuilderAccess.Run);
var modBuilder = assemblyBuilder.DefineDynamicModule("MyProxies");
// public class person
// {
var typeBuilder = modBuilder.DefineType(
"mypersonproxy",
TypeAttributes.Public | TypeAttributes.Class,
typeof(object),
new[] { typeof(Iperson) });
//      private person _realObject;
var fieldBuilder = typeBuilder.DefineField(
"_realObject",
typeof(person),
FieldAttributes.Private);
//event
var field = typeBuilder.DefineField("SomeththingHappened", typeof(SomeththingHappenedEventHandler), FieldAttributes.Private);
var eventInfo = typeBuilder.DefineEvent("SomeththingHappened", EventAttributes.None, typeof(SomeththingHappenedEventHandler));
//add
var addMethod = typeBuilder.DefineMethod("add_SomeththingHappened",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
CallingConventions.Standard | CallingConventions.HasThis,
typeof(void),
new[] { typeof(SomeththingHappenedEventHandler)});
var generator = addMethod.GetILGenerator();
var combine = typeof(Delegate).GetMethod("Combine", new[] { typeof(Delegate), typeof(Delegate) });
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Call, combine);
generator.Emit(OpCodes.Castclass, typeof(SomeththingHappenedEventHandler));
generator.Emit(OpCodes.Stfld, field);
generator.Emit(OpCodes.Ret);
eventInfo.SetAddOnMethod(addMethod);
//remove
var removeMethod = typeBuilder.DefineMethod("remove_SomeththingHappened",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
CallingConventions.Standard | CallingConventions.HasThis,
typeof(void),
new[] { typeof(SomeththingHappenedEventHandler) });
var remove = typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) });
var removator = removeMethod.GetILGenerator();
removator.Emit(OpCodes.Ldarg_0);
removator.Emit(OpCodes.Ldarg_0);
removator.Emit(OpCodes.Ldfld, field);
removator.Emit(OpCodes.Ldarg_1);
removator.Emit(OpCodes.Call, remove);
removator.Emit(OpCodes.Castclass, typeof(SomeththingHappenedEventHandler));
removator.Emit(OpCodes.Stfld, field);
removator.Emit(OpCodes.Ret);
eventInfo.SetRemoveOnMethod(removeMethod);
//      public mypersonproxy(person arg1)
//      {
var constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.HasThis,
new[] { typeof(person) });
var contructorIl = constructorBuilder.GetILGenerator();
contructorIl.Emit(OpCodes.Ldarg_0);
contructorIl.Emit(OpCodes.Ldarg_1);
contructorIl.Emit(OpCodes.Stfld, fieldBuilder);
contructorIl.Emit(OpCodes.Ret);
//      }
//      public void Work(string arg1)
//      {
var methodBuilder = typeBuilder.DefineMethod("Work",
MethodAttributes.Public | MethodAttributes.Virtual,
typeof(void),
new[] { typeof(string) });
typeBuilder.DefineMethodOverride(methodBuilder,
typeof(Iperson).GetMethod("Work"));
var tweetIl = methodBuilder.GetILGenerator();
//          Console.WriteLine("Hello before!");
tweetIl.Emit(OpCodes.Ldstr, "Hello before!");
tweetIl.Emit(OpCodes.Call, typeof(Console)
.GetMethod("WriteLine", new[] { typeof(string) }));
//raise probably something wrong here
var eventmethodBuilder = typeBuilder.DefineMethod("OnSomeththingHappened",
MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
typeof(void),
new[] { typeof(string) });
var methodgenerator = eventmethodBuilder.GetILGenerator();
var returnLabel = methodgenerator.DefineLabel();
var eventArgsCtor = typeof(PropertyChangedEventArgs).GetConstructor(new[] { typeof(string) });
methodgenerator.DeclareLocal(typeof(PropertyChangedEventHandler));
methodgenerator.Emit(OpCodes.Ldarg_0);
methodgenerator.Emit(OpCodes.Ldfld, field); 
methodgenerator.Emit(OpCodes.Stloc_0);
methodgenerator.Emit(OpCodes.Ldloc_0);
methodgenerator.Emit(OpCodes.Brfalse, returnLabel);
methodgenerator.Emit(OpCodes.Ldloc_0);
methodgenerator.Emit(OpCodes.Ldarg_0);
methodgenerator.Emit(OpCodes.Ldarg_1);
methodgenerator.Emit(OpCodes.Newobj, eventArgsCtor);
methodgenerator.Emit(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke"));
methodgenerator.MarkLabel(returnLabel);
methodgenerator.Emit(OpCodes.Ret);
eventInfo.SetRaiseMethod(eventmethodBuilder);

//          _realObject.Work(arg1);
tweetIl.Emit(OpCodes.Ldarg_0);
tweetIl.Emit(OpCodes.Ldfld, fieldBuilder);
tweetIl.Emit(OpCodes.Ldarg_1);
tweetIl.Emit(OpCodes.Call,
fieldBuilder.FieldType.GetMethod("Work"));
//          Console.WriteLine("Hello after!");
tweetIl.Emit(OpCodes.Ldstr, "Hello after!");
tweetIl.Emit(OpCodes.Call, typeof(Console)
.GetMethod("WriteLine", new[] { typeof(string) }));
tweetIl.Emit(OpCodes.Ret);
//      }
// }

return typeBuilder.CreateType();
}
static void Main(string[] args)
{
Boss boss1 = new Boss();
var type = CreateDynamicProxyType();
var dynamicProxy = (Iperson)Activator.CreateInstance(
type, new object[] { new person() });
dynamicProxy.SomeththingHappened += boss1.HeardIt;
dynamicProxy.Work("fill the excel documents");
}
}
}

在代理上生成 Work 方法时,您似乎忘记发出 IL 以调用SomeththingHappened.Invoke(),您必须添加

tweetIl.Emit(OpCodes.Ldarg_0);
tweetIl.Emit(OpCodes.Ldfld, field);
tweetIl.Emit(OpCodes.Callvirt, typeof(SomeththingHappenedEventHandler).GetMethod("Invoke"));

tweetIl.Emit(OpCodes.Call, fieldBuilder.FieldType.GetMethod("Work"));之后(假设您希望在调用_realObject.Work(...)之后引发事件(。

如果要添加空检查以确保SomeththingHappenednull则可以改用此版本

Label retLabel = tweetIl.DefineLabel();
tweetIl.Emit(OpCodes.Ldarg_0);
tweetIl.Emit(OpCodes.Ldfld, field);
tweetIl.Emit(OpCodes.Brfalse_S, retLabel);
tweetIl.Emit(OpCodes.Ldarg_0);
tweetIl.Emit(OpCodes.Ldfld, field);
tweetIl.Emit(OpCodes.Callvirt, typeof(SomeththingHappenedEventHandler).GetMethod("Invoke"));
// some other code if you want
tweetIl.MarkLabel(retLabel); //if not null ends here
tweetIl.Emit(OpCodes.Ret);

最新更新