Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSIL - how do you invoke a private method from MSIL?

I'm writing a "weak event factory" - code which converts any Delegate into a new delegate with an identical signature, but with implementing a WeakReference on the target. I'm using MSIL to avoid calls to Delegate.CreateDelegate (which performance have shown to be slow).

The weak reference delegates work perfectly as long as the underlying method (the Method of the original delegate), was declared public. As soon as a private or anonymous method is used, the MSIL bombs at run time with a MethodAccessException.

Using compiled expression trees, I've been able to invoke private methods, so it must be possible to dynamically emit MSIL which invokes a private method. ...so what's wrong with the following?

        // var target = this.Target
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Callvirt, targetPropGetter);         
        il.Emit(OpCodes.Stloc, ilTarget);            

        // if(target != null)
        // {
        il.Emit(OpCodes.Ldloc, ilTarget);
        il.Emit(OpCodes.Brfalse_S, ilIsNullLabel);

        //      Method( @target, parm1, parm2 ...);
        il.Emit(OpCodes.Ldloc, ilTarget);                  // this = Target
        short argIndex = 1;
        foreach (var parm in delgParams)                   // push all other args
            il.Emit(OpCodes.Ldarg, argIndex++);

        il.Emit(OpCodes.Callvirt, delegat.Method);   // <-- Bombs if method is private
        il.Emit(OpCodes.Ret);

        // }
        il.MarkLabel(ilIsNullLabel);

So what's the secret to invoking a private member? Reflection can do it, expression trees can do it... why is the above code failing?


EDIT: Much thanks to all of you who provided answers here. It turns out that the only solution which consistently worked in my context was to use generic delegates (Action)... because Action originates from the mscorlib, the JIT seems perfectly happy to let it invoke a private method. try using your own delegate and the JIT pukes just the same as if you emit a Call or Callvirt directly to the target.

Anyone who's interested in seeing the working code can head over to codeplex - the answers given here helped in implementing the WeakDelegate capabilities.

like image 786
Mark Avatar asked Oct 26 '10 21:10

Mark


People also ask

How to call a private method from another class?

We can call the private method of a class from another class in Java (which are defined using the private access modifier in Java). We can do this by changing the runtime behavior of the class by using some predefined methods of Java. For accessing private method of different class we will use Reflection API.

How do I call a private method in C#?

Private Methods can only be used inside the class. To set private methods, use the private access specifier. Private access specifier allows a class to hide its member variables and member functions from other functions and objects. Only functions of the same class can access its private members.

Can we access private method from outside class PHP?

PHP - Access Modifiers This is default. protected - the property or method can be accessed within the class and by classes derived from that class. private - the property or method can ONLY be accessed within the class.

Can we access private method in java?

You can call the private method from outside the class by changing the runtime behaviour of the class. With the help of java. lang. Class class and java.


2 Answers

Are you inserting your IL into a DynamicMethod or into a method within a dynamic assembly? As I understand it, there is no way to skip visibility checks from within a dynamic assembly, but you can skip them when using a DynamicMethod (see here).

like image 171
kvb Avatar answered Nov 15 '22 06:11

kvb


The solution (to my particular problem), was to used delegates instead of direct method calls. You can comfortably construct an open delegate and pass it to the IL code, and then when the IL code invokes the delegate's Invoke method, the JIT accepts the pattern as legal and allows the invoke of the private methods.

Like I said, this is a solution (which happily allows runtime-generated code to call private methods), though it still doesn't explain how technolgies like Expression Trees and Reflection manage to call private methods.

like image 22
Mark Avatar answered Nov 15 '22 04:11

Mark