Skip to content

Instantly share code, notes, and snippets.

@einarwh
Created April 28, 2012 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save einarwh/2521425 to your computer and use it in GitHub Desktop.
Save einarwh/2521425 to your computer and use it in GitHub Desktop.
Code to inject add and remove methods for the event handler.
private MethodDefinition CreateAddPropertyChangedMethod()
{
return CreatePropertyChangedEventHookupMethod(
"add_PropertyChanged",
"Combine");
}
private MethodDefinition CreateRemovePropertyChangedMethod()
{
return CreatePropertyChangedEventHookupMethod(
"remove_PropertyChanged",
"Remove");
}
private MethodDefinition CreatePropertyChangedEventHookupMethod(
string eventHookupMethodName,
string delegateMethodName)
{
// .method public final hidebysig specialname newslot virtual
// instance void add_PropertyChanged (
// class [System]System.ComponentModel.PropertyChangedEventHandler 'value'
// ) cil managed
var methodDef = new MethodDefinition(eventHookupMethodName,
MethodAttributes.Public |
MethodAttributes.Final |
MethodAttributes.HideBySig |
MethodAttributes.SpecialName |
MethodAttributes.NewSlot |
MethodAttributes.Virtual,
_types.Void);
var paramDef = new ParameterDefinition("value",
ParameterAttributes.None,
_types.PropertyChangedEventHandler);
methodDef.Parameters.Add(paramDef);
methodDef.Body.MaxStackSize = 3;
for (int i = 0; i < 3; i++)
{
var v = new VariableDefinition(_types.PropertyChangedEventHandler);
methodDef.Body.Variables.Add(v);
}
methodDef.Body.InitLocals = true;
var il = methodDef.Body.GetILProcessor();
Action<OpCode> op = x => il.Append(il.Create(x));
// IL_0000: ldarg.0
op(OpCodes.Ldarg_0);
// IL_0001: ldfld class [System]System.ComponentModel.PropertyChangedEventHandler Voodoo.ViewModel.GoalViewModel::PropertyChanged
var eventHandlerFieldDef = _typeDef.Fields
.FirstOrDefault(f => f.Name == PropertyChangedFieldName);
il.Append(il.Create(OpCodes.Ldfld, eventHandlerFieldDef));
// IL_0006: stloc.0
op(OpCodes.Stloc_0);
// // loop start (head: IL_0007)
// IL_0007: ldloc.0
var loopTargetInsn = il.Create(OpCodes.Ldloc_0);
il.Append(loopTargetInsn);
// IL_0008: stloc.1
op(OpCodes.Stloc_1);
// IL_0009: ldloc.1
op(OpCodes.Ldloc_1);
// IL_000a: ldarg.1
op(OpCodes.Ldarg_1);
// IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
var combineMethodReference = new MethodReference(
delegateMethodName,
_types.Delegate,
_types.Delegate);
var delegateParamDef = new ParameterDefinition(_types.Delegate);
combineMethodReference.Parameters.Add(delegateParamDef);
combineMethodReference.Parameters.Add(delegateParamDef);
il.Append(il.Create(OpCodes.Call, combineMethodReference));
// IL_0010: castclass [System]System.ComponentModel.PropertyChangedEventHandler
il.Append(il.Create(OpCodes.Castclass,
_types.PropertyChangedEventHandler));
// IL_0015: stloc.2
op(OpCodes.Stloc_2);
// IL_0016: ldarg.0
op(OpCodes.Ldarg_0);
// IL_0017: ldflda class [System]System.ComponentModel.PropertyChangedEventHandler Voodoo.ViewModel.GoalViewModel::PropertyChanged
il.Append(il.Create(OpCodes.Ldflda, eventHandlerFieldDef));
// IL_001c: ldloc.2
op(OpCodes.Ldloc_2);
// IL_001d: ldloc.1
op(OpCodes.Ldloc_1);
// IL_001e: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class [System]System.ComponentModel.PropertyChangedEventHandler>(!!0&, !!0, !!0)
// var declaringTypeRef = _typeDef.Module.Import(typeof(Interlocked));
var declaringTypeRef = _types.Interlocked;
var elementMethodRef = new MethodReference(
"CompareExchange",
_types.Void,
declaringTypeRef);
var genParam = new GenericParameter("!!0", elementMethodRef);
elementMethodRef.ReturnType = genParam;
elementMethodRef.GenericParameters.Add(genParam);
var firstParamDef = new ParameterDefinition(
new ByReferenceType(genParam));
var otherParamDef = new ParameterDefinition(genParam);
elementMethodRef.Parameters.Add(firstParamDef);
elementMethodRef.Parameters.Add(otherParamDef);
elementMethodRef.Parameters.Add(otherParamDef);
var genInstanceMethod = new GenericInstanceMethod(elementMethodRef);
genInstanceMethod.GenericArguments.Add(
_types.PropertyChangedEventHandler);
il.Append(il.Create(OpCodes.Call, genInstanceMethod));
// IL_0023: stloc.0
op(OpCodes.Stloc_0);
// IL_0024: ldloc.0
op(OpCodes.Ldloc_0);
// IL_0025: ldloc.1
op(OpCodes.Ldloc_1);
// IL_0026: bne.un.s IL_0007
il.Append(il.Create(OpCodes.Bne_Un_S, loopTargetInsn));
// // end loop
// IL_0028: ret
op(OpCodes.Ret);
return methodDef;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment