Monday, October 23, 2006

How to: Execute (another's class) private methods

Applies to C# (Tested using C# 2.0)

The access modifier private is the most restrictive one, allowing access only to the containing type

Every once in a while we want to access a private method in some class that we don't have source code for (BCL anyone?); usually we shouldn't have to do that, but in case you need it for whatever reason, here's a way of doing it:

Lets create a test class to be used as our example:

public class TestClass {
public TestClass() {
}
private void HiddenMethod() {
Console.WriteLine("secret method, should only be called from the containing class itself");
}
private string HiddenMethodWithParams(string firstName, int age) {
return string.Format("hello {0}, you are {1} years old", firstName, age);
}
}

Basically this class is useless, because it doesn't expose any public methods... unless we had access to the private methods (okay, it's still useless, but this is just my lame example)


Now, let's see how we can access those private methods

TestClass tc = new TestClass();
Type testClaseType = typeof(TestClass);

MethodInfo hiddenMethod =
testClaseType.GetMethod("HiddenMethod",
BindingFlags.NonPublic | BindingFlags.Instance);
hiddenMethod.Invoke(tc, null);

MethodInfo hiddenMethodWithParams =
testClaseType.GetMethod("HiddenMethodWithParams",
BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[2] { typeof(string), typeof(int) }, null);
string result = (string)hiddenMethodWithParams.Invoke(tc, new object[2] { "Eber", 25 });
Console.WriteLine("result: "+ result);

Let's go in detail:



  1. 1- The first line just creates an instance (tc) of the class (TestClass) we're interested in (because it contain those precious private methods that we want)
  2. 2- The second line gets the type of the class, in this case it would be TestClass, this variable (testClassType) is used later on to query that class about it's methods.
  3. 3- Then it gets interesting, we acquire a "pointer" to the "hiddenMethod" private method and store it in the hiddenMethod variable; we do this by querying the testClassType variable, passing the name of the method; the parameter BindingFlags.NonPublic means you want a member which is not public (private in this case) and BindingFlags.Instance means you want an instance method (as opposed to an static one), remember that static methods don't get executed from an instance, but are called directly from the class.
  4. 4- Now that we have a pointer to the method we just need to call it, all we have to do is call the Invoke method of our hiddenMethod variable, we pass tc as a parameter, this is the instance on which we are executing the method (tc is the instance we created on the first line)

That's pretty much all we have to do, but of course a method that doesn't take any parameters and doesn't return anything is not very useful, so I included an example of calling a more complex method, one that takes parameters and returns something.


We just have to change a few things to make it work:


On step 3, where we get the pointer to the method, we need to pass information about the method's parameter types, this information is passed in an array, if you go to the top and look at the TestClass, you'll see that the method HiddenMethodWithParams takes 2 parameters, a string and an int, now let's see how we specify that:


new Type[2] { typeof(string), typeof(int) }


Which means: 2 parameters, the first one is a string, the second an int


You could (of course) pass any type of parameter here


Now we have the pointer to the method we want, but this method returns something, so we'll have to change the way we call it:


string result = (string)hiddenMethodWithParams.Invoke(tc, new object[2] { "Eber", 25 });


Here we create a variable to store the result, then we call the method, casting it's result to the type we know it returns (a string), the parameter tc remains the same, remember this is the instance on which we are calling the method, last we need to pass the parameters to the function, the way of passing the parameters is very similar to the way we specified their types


new object[2] { "Eber", 25 }


Which translates to: 2 parameters, the first one is "Eber", the second:25


That's it! try not to abuse this technique, full source can be found here


side node: while running Live Writer spell checking it suggested that I should call my test Class Testicles instead of TestClass


kick it on DotNetKicks.com

5 comments:

Orion Edwards said...

You can also avoid the annoying intermediate MethodInfo by using

typeof(obj).InvokeMember( ... )

Anonymous said...

"try not to abuse this technique"...Simply using this method seems to be abuse. Obviously the whole point of marking a method private is to prevent access by others. Using this in your code is just asking for trouble when new versions are released. I'd like to see an example where this is actually necessary. The BCL example is just poor programming practice. Microsoft, or any other framework provider, has every right to remove or modify private methods in future releases...

Anonymous said...

Your code works only for methods with in parameters. When you have ref/ out parameters the things get a lot messier.

BlackTigerX said...

is not that different, you just pass another array indicating the modifiers, I'll post another example that includes those

Olivier Dagenais said...

Watch out, you need a special permission to do this (i.e. ReflectionPermission), otherwise reflection will only allow you to access public members.

Here's a blog post about just that.