C Sharp Reflection hack to call any class or any method.

Posted in software by Christopher R. Wirz on Mon Aug 14 2017



Reflection in C# is beyond powerful. Similar to C++ in which nothing is actually private, the same is true of C#. Reflection provides objects (of type Type) that describe assemblies, modules, and types.

Note: Reflection is designed to examine and instantiate types in an assembly - and building new types at runtime.

Once you obtain a Type, there are many ways you can discover information about the members of that type. You can find out about all the type's members by calling the Type.GetMembers method, which obtains an array of MemberInfo objects describing each of the members of the current type.


/// <summary>
///     Gets an instance of a type using whatever constructor it can find.
/// </summary>
/// <param name="type">The type</param>
/// <returns>An object instance of type or null</returns>
public static object CreateInstance(this Type type)
{
	if (type == null) { return null; }
	object obj = null;
	try
	{
		// just try for a default constructor
		obj = Activator.CreateInstance(type);
	}
	catch {
		// ignored
	}
	if (obj != null) { return obj; }
	try
	{
		// Everything has to have a parameter-less constructor somewhere
		obj = type.GetConstructor(
			BindingFlags.NonPublic | BindingFlags.Instance, // binding flag bit-mask
			null, // binder
			Type.EmptyTypes, // what the constructor should look like
			null // constructor parameter processing information
		).Invoke(null);
	}
	catch
	{
		// Ignored
	}
	return obj;
}

/// <summary>
///     Gets the type from a string
/// </summary>
/// <param name="fulllyQualifiedName">Name of the fully qualified.</param>
/// <returns>A type or null</returns>
public static Type GetType(string fulllyQualifiedName)
{
	Type type = null;
	try
	{
		type = Type.GetType(fulllyQualifiedName);
	}
	catch
	{
		// Ignored
	}
	if (type != null) { return type; }
	foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
	{
		try
		{
			type = asm.GetType(fulllyQualifiedName);
			if (type != null) { return type; }
		}
		catch
		{
			// Ignored
		}
	}
	foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
	{
		try
		{
			type = asm.GetTypes().FirstOrDefault(t => t.FullName.Equals(fulllyQualifiedName));
			if (type != null) { return type; }
		}
		catch
		{
			// Ignored
		}
	}
	foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
	{
		try
		{
			type = asm.GetTypes().FirstOrDefault(t => t.Name.Equals(fulllyQualifiedName));
			if (type != null) { return type; }
		}
		catch
		{
			// Ignored
		}
	}
	return type;
}

/// <summary>
///     Gets the methods defined by the class
/// </summary>
/// <param name="t">The type</param>
/// <returns>A collection of method information</returns>
public static IEnumerable<MethodInfo> GetClassDefinedMethods(this Type t)
 => t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
	.Where(m =>
		// it is indeed a method
		m.MemberType == MemberTypes.Method
		// The type declares the method
		&& m.DeclaringType == t
		// Make sure it's not a method made by the compiler
		&&  !m.CustomAttributes.Any(c => c.AttributeType.Name == "CompilerGeneratedAttribute")
		// Make sure it's not a reserved name like get_ or set_
		&& !m.IsSpecialName
	)
	// To be safe, you can remove methods often defined on System.Object
	.Where(m => !(m.Name.Equals("Equals") ||
			m.Name.Equals("GetHashCode") ||
			m.Name.Equals("GetType") ||
			m.Name.Equals("ToString") ||
			m.Name.Equals("Compare") ||
			m.Name.Equals("CompareTo") ||
			m.Name.Equals("Finalize") ||
			m.Name.Equals("Clone") ||
			m.Name.Equals("MemberwiseClone") ||
			m.Name.Equals("ReferenceEquals")));

We can now experiment with the following class, which is purely private:


/// <summary>
///     A class trying to hide everything
/// </summary>
private class SecretClass {
	/// <summary>
	///     A private method
	/// </summary>
	private void RunMethod {
		System.Console.WriteLine("You found me");
	}
}

Now we see that we can call the class and its hidden method


var t = Extensions.GetType("SecretClass");
Assert.IsNotNull(t);
var m = t.GetClassDefinedMethods();
Assert.IsTrue(m.Count() == 1);
var o = t.CreateInstance();
var mi = m.FirstOrDefault(mi => mi.GetParameters().Length == 0);
Assert.IsNotNull(mi);
mi.Invoke(o, null); // displays "You found me"

So what can we do with this awesome power? Make Singletons of course!


/// <summary>
///     A class designed to be used by its instance
/// </summary>
class SingletonClass
{
	private SingletonClass() { }

	/// <summary>
	///     The instance of the class
	/// </summary>
	public static SingletonClass Instance { get; private set; } = new SingletonClass();

	/// <summary>
	///     Gets or sets the identifier.
	/// </summary>
	public int ID { get; set; } = 1;

}

/// <summary>
///     Takes a class type and makes a singleton
/// </summary>
/// <typeparam name="T">The type to make a singleton for</typeparam>
public class Singleton<T> where T : class
{
	/// <summary>
	///     Gets the instance.
	/// </summary>
	public static T Instance { get; private set; } = typeof(T).CreateInstance() as T;

	// private constructor
	private Singleton()
	{
	}
}

Now we can test the creation of a singleton, vs the class's singleton (we see what is the same and what is different):


var i = SingletonClass.Instance;
i.ID = 3;
var i2 = Singleton<SingletonClass>.Instance;
i2.ID = 4;
var i3 = Singleton<SingletonClass>.Instance;
i3.ID = 5;
Assert.AreNotEqual(i.ID, i2.ID);
Assert.AreEqual(i3.ID, i2.ID);

The SingletonClass has a different instance than the Singleton<SingletonClass> instance. Now you can make a Singleton of any class!