views:

201

answers:

5

I was wondering if it was possible to dynamically inject a function parameter at runtime. For e.g. I have a class with two overloaded methods say

Class C1
{
    public static void Func1(object o)
    {
    }

    public static void Func1()
    {
    }       
}

Class C2
{

    public void Func1()
    {
       C1.Func1();
    }
}

Now, is it possible to dynamically replace the call to Func1() with a call to the overloaded method C1.Func1(object o) passing in either 'this' or the type object as the parameter.

So, in affect when I call C1.Func1(), my code should call C1.Func1(this);

+1  A: 

Several options:

  1. Decompile the binary to MSIL, do the changes manually and recompile it.
  2. User the .NET profiling API to inject code, here is an [article] discussing it.
  3. Similar issue code-injection-with-c

The code injection would be to intercept the function without the argument, and recall the function with an argument.

Am
A: 

As your method is static there is no way of obtaining the calling object.

Your options are to either make your methods non static and create a C1 object, or, pass the C2 (this) object in as a parameter.

Robin Day
+3  A: 

I am assuming that by "dynamic" you mean a post-compile time solution, but not necessarily at runtime. The latter would be more challenging but could be done. For the former it's rather easy if you know some IL. I note that C2.Func1 compiles to something like

.method public hidebysig instance void Func1() cil managed {
    call void SomeNamespace.C1::Func1() 
    ret 
}

which you can easily replace with

.method public hidebysig instance void Func1() cil managed {
    ldarg.0
    call void SomeNamespace.C1::Func1(object)
    ret 
}

This is because argument zero in an instance method is always the this reference for the current instance and we can push it on the stack with the instruction ldarg.0. Moreover, we simply replace the signature of the method that we are invoking from the parameterless method to the method accepting a single object as a parameter.

You can easily decompile to IL using ildasm and recompile using ilasm.

Jason
Thanks Jason, that certainly works, however could you explain a bit more about the other option that you suggested, i.e. at runtime, would that mean using the Profiler API as suggested by Am?
ilias
+2  A: 

You can use an extension method:

public static class C1Extensions
{
    public static void Func1(this C1 o)
    {
        // ...
    }
}

public class C1
{
    public void Foo()
    {
       this.Func1();
    }
}
Bryan Watts
Beat me by like 30 seconds...
Seth Petry-Johnson
+1, was just about to post the same thing, however, still requires the "this" keyword to call it.
Robin Day
A: 

Have you thought about using extension methods to do this?

public static class C1WrappingExtensions {
    public static void Func1(this object instance) {
        C1.Func(instance);
    }
}

// Now you can just call Func1() on any object...
var me = new Whatever();
me.Func1();
Seth Petry-Johnson