You can do it at runtime using a .NET AOP Framework event if it is not the the main purpose of this kind of framework.
I actively work on a new one which can handle it event if your method is not virtual.
You can take a look on NConcern .NET runtime AOP Framework
The monkey patch "aspect" :
public class MonkeyPatch : IAspect
{
static public void Patch(MethodInfo oldMethod, MethodInfo newMethod)
{
//update monkey patch dictionary
MonkeyPatch.m_Dictionary[oldMethod] = newMethod;
//release previous monkey patch for target method.
Aspect.Release<MonkeyPatch>(oldMethod);
//weave monkey patch for target method.
Aspect.Weave<MonkeyPatch>(oldMethod);
}
static private Dictionary<MethodInfo, MethodInfo> m_Dictionary = new Dictionary<MethodInfo, MethodInfo>();
public IEnumerable<IAdvice> Advise(MethodInfo method)
{
if (MonkeyPatch.m_Dictionary.ContainsKey(_Method))
{
yield return Advice(MonkeyPatch.m_Dictionary[_Method]);
}
}
}
Patch :
static public void main(string[] args)
{
//create Boo2, a dynamic method with Boo signature.
var boo2 = new DynamicMethod("Boo2", typeof(void), new Type[] { typeof(Foo) }, typeof(Foo), true);
var body = boo2.GetILGenerator();
//Fill your ILGenerator...
body.Emit(OpCodes.Ret);
//Apply the patch
MonkeyPatch.Patch(typeof(Foo).GetMethod("Boo"), boo2);
}
in the second hand, if you just need to call something after the original call, you are in AOP aim and you can do it like that...
Observation Aspect :
public class Observation : IAspect
{
static public void Observe(MethodInfo method, Action action)
{
//update observation dictionary
Observation.m_Dictionary[method] = action;
//release observation aspect for target method
Aspect.Release<Observation>(method);
//weave observation aspect for target method.
Aspect.Weave<Observation>(method);
}
static private Dictionary<MethodInfo, Action> m_Dictionary = new Dictionary<MethodInfo, Action>;
public IEnumerable<IAdvice> Advice(MethodInfo method)
{
if (Observation.m_Dictionary.ContainsKey(method))
{
yield return Advice.Basic.After(Observation.m_Dictionary[method]);
}
}
}
Use case :
static public void main(string[] args)
{
Observation.Observe(typeof(Foo).GetMethod("Boo"), () => { /* paste here your notification code... */ });
}
protected virtual
? – Demodenaprotected virtual
, however I'm actually looking for solution that will allow to not touch the original code. – FledaFoo
. Test is finished whenBoo
is finished. I need to put some notification intoBoo
method in order to stop my test. – FledaBoo
is kind of spaghetti code. There is anif
inside. My test is finished within thatif
. I don't want to do any refactoring of that method. Just make a copy of it, find thatif
inside that copy and attach some notification after that. The key thing here is to not amend originalFoo
norBoo
. – FledaBoo
and the calling method should be in different classes so you can mock boo the usual way. Alternatively make Boointernal protected virtual
(assuming you have InternalsVisibleTo set for your test assembly) and create a derived class Foo2 in your test where you can override Boo. – Demodena