Suppose I wanted to emit
public event PropertyChangedHandler PropertyNameChanged;
How would I do this? Would I need to define a backing field like I would a property? I can't find a single example of how to use the EventBuilder and how do I actually raise an event?
I know that this is old question and this answer will probably never be accepted, but I get here from Google so probably other people will get here to. Just for those people, here is a correct answer: To create and event you have to:
{EventName}
{EventName}
add_{EventName}
and remove_{EventName}
Second and forth is covered by Dmitry answer, but here is a complete code. Of course you have to change EventName
and EventType
for values correct for your event.
var field = typeBuilder.DefineField("{EventName}", typeof({EventType}), FieldAttributes.Private);
var eventInfo = typeBuilder.DefineEvent("{EventName}", EventAttributes.None, typeof({EventType}));
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);
Raise method. Not required, but there is really no point for creating event if you do not have method to raise it. Unless you are doing some hocus-pocus with reflection or calling value of event Delegate.
Anyway here is the code for this method. Of course you have to obtain correct constructor of some XXXEventArgs
type, that is used inside of event, first. Name of this raise method also may be different, but following some pattern is generally better idea (like 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 do not have be virtual, or protected (MethodAttributes.Family
), but it is better to have this method non-public and overridable. Types of parameter also have to be different and compatible with XXXEventArgs
type constructor. You can also have more parameters in this method but I advice against it since it makes IL more complicated (you should do as little in IL as possible as favor for yourself and your sanity).
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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With