Reflection Series – Part 1: From Class Name to Instance

I’m starting a series on how I’ve used reflection for my projects. I saw that I’ve actually made a lot of stuff out of it and I just can’t put them all in one long post. I’ll start with a brief introduction to what reflection is and discuss a simple usage that has huge potential.

Reflection refers to the set of APIs that “makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing the names of the classes, methods etc. at compile time. It is also possible to instantiate new objects, invoke methods and get/set field values using such API.” Basically, you can do things like traversing all the properties of a class instance and invoke them or assign value to them. You can list the class names that derive from a certain class. You can determine the attributes attached to a property or class. You can do a lot. The limit is your imagination.

Luckily, Unity’s C# environment have access to such API. The namespace is aptly called System.Reflection.

Loading a class name (string) into an actual class instance

Say you have the following class:

namespace Game {
    class Shoot : Command {
        public Shoot() {
            // Default constructor
        }

        public void Execute() {
            ... // Detailed shooting routines
        }
    }
}

By using reflection, we can load a Shoot instance by its full class name. First thing to do is to determine the Type that a class name points to. There’s a method for this named Type.GetType() but this is insufficient. Sometimes, it returns null even when the class exists. I’ve made a utility method for this which I found somewhere on the internet years ago:

public static Type GetType(string typeName) {
    // Try Type.GetType() first. This will work with types defined
    // by the Mono runtime, in the same assembly as the caller, etc.
    Type type = Type.GetType(typeName);

    // If it worked, then we're done here
    if(type != null) {
        return type;
    }

    // Attempt to search for type on the loaded assemblies
    Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
    foreach(Assembly assembly in currentAssemblies) {
        type = assembly.GetType(typeName);
        if(type != null) {
            return type;
        }
    }

    // If we still haven't found the proper type, we can enumerate all of the
    // loaded assemblies and see if any of them define the type
    var currentAssembly = Assembly.GetExecutingAssembly();
    var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
    foreach(var assemblyName in referencedAssemblies) {
        // Load the referenced assembly
        var assembly = Assembly.Load(assemblyName);
        if(assembly != null) {
            // See if that assembly defines the named type
            type = assembly.GetType(typeName);
            if(type != null) {
                return type;
            }
        }
    }

    // The type just couldn't be found...
    return null;
}

We also need the following utility code to get the constructor with no parameters.

public static ConstructorInfo ResolveEmptyConstructor(Type type) {
   ConstructorInfo[] constructors = type.GetConstructors();
   foreach(ConstructorInfo constructor in constructors) {
       // we only need the default constructor
       if(constructor.GetParameters().Length == 0) {
           return constructor;
       }
   }

   // Can't resolve appropriate constructor. Client code should check for this.
   return null;
}

Then we use the following sequence of code to load the instance.

Type type = TypeUtils.GetType("Game.Shoot"); // Full class name (include the namespaces)
ConstructorInfo constructor = TypeUtils.ResolveEmptyConstructor(type);
object[] EMPTY_PARAMETERS = new object[0]; // This can be made into a static variable

// Invoke the constructor
// Can also be cast to Shoot but I'd like to point out a possible usage
Command command = (Command)constructor.Invoke(EMPTY_PARAMETERS);

// Use the instance
command.Execute();

That wasn’t so hard, was it? But how can this used? We just made an instance from a mere string. Imagine if that string was from an XML file, or JSON, or Unity editor, or whatever. We could build an editor that collects these class names then in the game, we load those classes and use them. I’ve used this a lot in our editors. Just this week, I was working on our Grants editor. In Academia, grants act as resource boost and also guide the player on what to do next. Each grant has a set of requirements. Each requirement is implemented as a class that derives from a base class. The grant data then has a list of requirement class names. I made an editor where the designer can input the values for each grant data and also define its requirements. In the game, I then load these requirement instances and use them.

GrantEditor

The following code can be used to get the types that are deriving from a parent type. This can be used to make something like a class selection browser.

Type[] types = Assembly.GetAssembly(parentType).GetTypes();
foreach (Type type in types) {
    if (type.IsSubclassOf(parentType) && !type.IsAbstract) {
        // Add to some container
        subclassList.Add(type);
    }
}

Hopefully, you have found this example usage of reflection useful. I plan to show more on the next part. But by then, you may have probably thought of more uses for it.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s