Skip to content

Instantly share code, notes, and snippets.

@einarwh
Created April 28, 2012 21:12
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/2522052 to your computer and use it in GitHub Desktop.
Save einarwh/2522052 to your computer and use it in GitHub Desktop.
Code to inject notification calls, optionally refactoring out original setter.
private void InjectNotification(MethodDefinition methodDef,
IEnumerable<string> propNames)
{
if (_notifyMethodDef == null || methodDef == null)
{
return;
}
if (HasMultipleReturnPoints(methodDef))
{
RefactorSetterAndInjectNotification(methodDef, propNames);
}
else
{
InjectNotificationDirectly(methodDef, propNames);
}
}
private bool HasMultipleReturnPoints(MethodDefinition methodDef)
{
return methodDef.Body.Instructions.Count(
insn => insn.OpCode == OpCodes.Ret) > 1;
}
private void RefactorSetterAndInjectNotification(
MethodDefinition oldMethodDef,
IEnumerable<string> propNames)
{
var methodName = "Refactored" + oldMethodDef.Name
.Substring(PropertySetterPrefix.Length) + "Setter";
var methodDef = new MethodDefinition(methodName,
oldMethodDef.Attributes,
oldMethodDef.ReturnType);
foreach (var oldParamDef in oldMethodDef.Parameters)
{
var paramDef = new ParameterDefinition(
oldParamDef.Name,
oldParamDef.Attributes,
oldParamDef.ParameterType);
methodDef.Parameters.Add(paramDef);
}
methodDef.Body = oldMethodDef.Body;
_typeDef.Methods.Add(methodDef);
oldMethodDef.Body = new MethodBody(oldMethodDef);
var il = oldMethodDef.Body.GetILProcessor();
Action<OpCode> op = x => il.Append(il.Create(x));
op(OpCodes.Ldarg_0);
op(OpCodes.Ldarg_1);
il.Append(il.Create(OpCodes.Call, methodDef));
op(OpCodes.Ret);
InjectNotificationDirectly(oldMethodDef, propNames);
}
private void InjectNotificationDirectly(MethodDefinition methodDef,
IEnumerable<string> propNames)
{
var il = methodDef.Body.GetILProcessor();
var returnInsn = il.Body.Instructions.Last();
foreach (var s in propNames)
{
var loadThis = il.Create(OpCodes.Ldarg_0);
var loadString = il.Create(OpCodes.Ldstr, s);
var callMethod = il.Create(OpCodes.Call, _notifyMethodDef);
il.InsertBefore(returnInsn, loadThis);
il.InsertBefore(returnInsn, loadString);
il.InsertBefore(returnInsn, callMethod);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment