Reflection

If you have scripting language that allows you to call C# (e.g. Powershell), or if you want to call undocumented private methods, then you need to learn how to use Reflection.

What is “reflection”?

It’s a way of programatically examining and calling code from an assembly (.dll/.exe) at runtime.

The examples here are in C#, but the concepts apply when you are using scripting languages that use .NET.

Load C# Objects

How would you use classes from a different dll without importing it? You could use Assembly.UnsafeLoadFrom("path to dll"); this will return an Assembly object, which you can use to create instances programatically.

var targetAssmbly = Assembly.UnsafeLoadFrom(@"\\pathTo\your.dll");
var instance = targetAssmbly.CreateInstance("Some.Class.In.Assembly");

Create C# Objects (w/Reflection)

Let’s start with two fundamental methods CreateInstance and GetType. These are instance methods in System.Reflection.Assembly.

CreateInstance is equivalent to programatically making a new object.

//this is the Reflection equivalent of doing var x = new System.Collections.ArrayList();
var x = "".GetType().Assembly.CreateInstance("System.Collections.ArrayList");

GetType is equivalent to getting a handle to a class so that you can call a static method on it.

//if you just want to call a static method
//(such as System.Convert.FromBase64String)
var convertType = "".GetType().Assembly.GetType("System.Convert")

Notes

Note that there is also a Type.GetType(string) static method that searches the current assembly for that Type. This can also be used.

Note that you are only allowed to access classes from the same assembly as ‘String’ (mscorlib.dll)

Invoking [private] methods

To invoke any method with parameters, you need to pass in the parameter list as an array of C# objects.

But in most scripting languages, there is no notion of a “type”. So how do you create a C# array of C# objects?

Answer: Use the ArrayList.Add(object) function to add objects of any type, then use the ArrayList.ToArray() to convert it to a C# array of objects.

There are two options that you can use to invoke methods. - with the method name: Type.GetMethod("nameOfMethod").Invoke(...) - get all the methods of the class, then select which one you want to invoke (by index): Type.GetMethods()[3].Invoke(...)

Questions you might have are: - how do you invoke a method on a class vs an instance?
- how do you invoke async methods? - how do you invoke private methods?

Invoking a static method on a class

//Example of how to dynamically invoke 'System.Convert.FromBase64String()'
"".GetType().Assembly.GetType("System.Convert").GetMethod("FromBase64String").Invoke(null, new string[]{"base64 string"});

The first argument to Invoke is the object you want to target. In this case, we are not calling this method on an object, so it is null. The second argument to Invoke is the parameter list for the method FromBase64String. It must be passed as an Object[].

Invoking an async method on an instance

Here is another example of reflectively invoking a method on an instance of an object. Note the dynamic declaration of resultsToAwait.

var targetAssmbly = Assembly.UnsafeLoadFrom(@"\\pathTo\your.dll");
var instance = targetAssmbly.CreateInstance("Some.Class.In.Assembly");
dynamic resultsToAwait = targetAssmbly.GetType("Some.Class.In.Assembly").GetMethod("GetStuffAsync").Invoke(instance, null); 
//'null' because GetStuffAsync does not need parameters

IEnumerable<dynamic> results = await resultsToAwait;
//assuming that the results return an IEnumerable, you have to check the return type.

Invoking Methods By Index

One reason for using this is if there are overloaded methods with the same number of parameters.

For example, Assembly.Load(AssemblyName) and Assembly.Load(byte[])

The first step is to list the methods - note that the methods can appear in a different order when you are running the code on a different machine.

This will list all the public methods of a given type.

MethodInfo[] allMethods = "".GetType().GetMethods();

Invoking Private Methods by index/name

You need to use these objects called ‘BindingFlags’ and use the method: GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)

var privateMethods = "".GetType()
	.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);

get yourself on the email list

//Powered by MailChimp - low volume, no spam

comments powered by Disqus