假设我想发光
public event PropertyChangedHandler PropertyNameChanged;
我该怎么做?我是否需要定义像我属性一样的支持字段?我找不到如何使用EventBuilder的单个示例,以及如何实际引发事件?
答案 0 :(得分:3)
我知道这是一个老问题,这个答案可能永远不会被接受,但我从谷歌来到这里,所以可能其他人会来这里。只为这些人,这是一个正确的答案: 要创建和事件,您必须:
{EventName}
{EventName}
add_{EventName}
和remove_{EventName}
Dmitry的回答涵盖了第二次,但这里有一个完整的代码。当然,您必须更改EventName
和EventType
以获取与您的活动相符的值。
var field = typeBuilder.DefineField("{EventName}", typeof({EventType}), FieldAttributes.Private);
var eventInfo = typeBuilder.DefineEvent("{EventName}", EventAttributes.None, typeof({EventType}));
添加访问者并删除访问者;它们非常相似。
var addMethod = typeBuilder.DefineMethod("add_{EventName}",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
CallingConventions.Standard | CallingConventions.HasThis,
typeof(void),
new[] { typeof({EventType}) });
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({EventType}));
generator.Emit(OpCodes.Stfld, field);
generator.Emit(OpCodes.Ret);
eventInfo.SetAddOnMethod(addMethod);
var removeMethod = typeBuilder.DefineMethod("remove_{EventName}",
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot,
CallingConventions.Standard | CallingConventions.HasThis,
typeof(void),
new[] { typeof({EventType}) });
var remove = typeof(Delegate).GetMethod("Remove", new[] { typeof(Delegate), typeof(Delegate) });
var generator = removeMethod.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Call, remove);
generator.Emit(OpCodes.Castclass, typeof(PropertyChangedEventHandler));
generator.Emit(OpCodes.Stfld, field);
generator.Emit(OpCodes.Ret);
eventInfo.SetRemoveOnMethod(removeMethod);
提高方法。不是必需的,但是如果你没有提高它的方法,那么创建事件真的没有意义。除非你正在做一些反射或调用事件代表值的hocus-pocus。
无论如何这里是这个方法的代码。当然,您必须首先获取在事件内使用的某些XXXEventArgs
类型的正确构造函数。这种提升方法的名称也可能不同,但遵循某种模式通常更好的想法(如下所示):
var methodBuilder = typeBuilder.DefineMethod("On{EventName}",
MethodAttributes.Family | MethodAttributes.Virtual | MethodAttributes.HideBySig |
MethodAttributes.NewSlot, typeof(void),
new[] { typeof(string) });
var generator = methodBuilder.GetILGenerator();
var returnLabel = generator.DefineLabel();
var eventArgsCtor = typeof({XXXEventArgs}).GetConstructor(new[] { typeof(string) });
generator.DeclareLocal(typeof({EventType}));
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, field);
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Brfalse, returnLabel);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldarg_1);
generator.Emit(OpCodes.Newobj, eventArgsCtor);
generator.Emit(OpCodes.Callvirt, typeof(PropertyChangedEventHandler).GetMethod("Invoke"));
generator.MarkLabel(returnLabel);
generator.Emit(OpCodes.Ret);
eventInfo.SetRaiseMethod(methodBuilder);
return methodBuilder;
此方法也不是虚拟的或受保护的(MethodAttributes.Family
),但最好将此方法设置为非公共和可覆盖。参数类型也必须与XXXEventArgs
类型构造函数不同并兼容。你也可以在这个方法中有更多的参数,但我建议反对它,因为它会使IL变得更复杂(你应该尽可能少地利用IL来帮助你自己和你的理智)。
答案 1 :(得分:1)
TypeBuilder myClass =
myModule.DefineType("MyClass", TypeAttributes.Public);
MethodBuilder onPropertyNameChanged= myClass.DefineMethod("OnPropertyNameChanged",
MethodAttributes.Public, typeof(void), new Type[]{typeof(Object)});
ILGenerator onPropertyNameChangedIl= onPropertyNameChanged.GetILGenerator();
onPropertyNameChangedIl.Emit(OpCodes.Ret);
// Create the event.
EventBuilder propertyNameChanged= myClass.DefineEvent("PropertyNameChanged", EventAttributes.None,
typeof(PropertyChangedHandler)); //should be declared before
propertyNameChanged.SetRaiseMethod(onPropertyNameChanged);
myClass.CreateType();