Created
April 28, 2012 19:14
-
-
Save einarwh/2521425 to your computer and use it in GitHub Desktop.
Code to inject add and remove methods for the event handler.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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