Saturday, October 20, 2007

Invoking a method that takes a pointer as an argument

I'm currently playing around with a cloned StringBuilder. This builder needs to call some methods on the String class which is internal, so reflection is the only way to call them. Usually that's no problem, but this time some of the methods accepted Char* as arguments and I haven't dealt with that before in reflection matters.

Getting the method info
The method I'm interested in is:

internal unsafe void AppendInPlace(char* value, int count, int currentLength)

If there were no overloads this would be pretty easy since then I wouldn't have to supply the Type.GetMethod method with an array of argument types for the method. But this method has 5 overloads, so I need to be specific to the GetMethod method. The problem is that I have not tried to get a type of a pointer before so I didn't know what to write.

By calling the Type.GetMethods method I get a list of all the methods that the String class has. In that list I find the specific overload of AppendInPlace and by examining the MethodInfo that is returned I can see what the type is called. It was actually pretty simple: System.Char*

Knowing that I can now create the array of types and get the correct MethodInfo instance:

   Type type = typeof( String );

   BindingFlags internalInstance = BindingFlags.NonPublic | BindingFlags.Instance;

   Type[] types = GetTypeArray( Type.GetType( "System.Char*" ), count.GetType(), currentLength.GetType() );

   MethodInfo info = type.GetMethod( "AppendInPlace", internalInstance, null, types, null );


Invoking the method
Now everything is good to go, we have the MethodInfo, the arguments and the object to invoke the method on, what can possibly go wrong? Oh yeah, you cannot pass a Char* to a method that takes an array of objects as MethodInfo.Invoke does. But luckily the solution was quite easy. You just have to create an instance of IntPtr using the Char* in the constructor, like this:

   Object[] objects = GetObjectArray( new IntPtr( value ), count, currentLength );

   info.Invoke( str, objects );


That's all there is to it.

0 comments: