How to use EventBuilder to create an event?

Suppose I wanted to emit

public event PropertyChangedHandler PropertyNameChanged; 

How can I do it? Should I define a support field, such as a property? I cannot find one example of how to use EventBuilder and how can I draw an event?

+6
source share
2 answers

I know this is an old question, and this answer will probably never be accepted, but I got here from Google, so other people will probably come here. For these people only, here is the correct answer: To create and event you need:

  • Create field {EventName}
  • Create an event with the same name {EventName}
  • Create and remove accessors (methods) add_{EventName} and remove_{EventName}
  • Create a raise method with some arbitrary name (or not, since this step is optional)

Secondly, this is the answer to Dmitry’s question, but here is the full code. Of course, you must change EventName and EventType for the values ​​appropriate for your event.

  • Event field

 var field = typeBuilder.DefineField("{EventName}", typeof({EventType}), FieldAttributes.Private); 
  1. Event

 var eventInfo = typeBuilder.DefineEvent("{EventName}", EventAttributes.None, typeof({EventType})); 
  1. Add accessor and remove accessor; they are very similar.

     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); 
  2. Raise the method. Not required, but it makes no sense to create an event if you have no way to raise it. Unless you are doing some kind of focus focus with the reflection or the calling value of the Delegate event. In any case, the code for this method is given here. Of course, you should get the correct constructor of some type XXXEventArgs , which is used inside the event, firstly. The name of this enhancement method may also be different, but after some template the idea is usually better (for example, below):

     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; 

    Also, this method is not virtual or protected ( MethodAttributes.Family ), but it is better to have this method non-public and redefined. Parameter types must also be different and compatible with a constructor of type XXXEventArgs . You may also have more parameters in this method, but I advise against it, since it makes IL more difficult (you should do as little as possible in IL, both about yourself and your sanity).

+2
source
  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(); 
+1
source

All Articles