Reflection Series – Part 3: Attributes are Magic

Attributes in C# are those things wrapped in “[]” that are sprinkled on classes, properties, or variables. In Unity, I usually use [SerializeField] so that a variable becomes editable in the editor but still remains private or protected in code if I wanted to. There are other attributes, too, like Range, ExecuteInEditMode, HideInInspector, DisallowMultipleComponent, etc. Somewhere in Unity’s processes access these attributes through reflection and executes code that the attribute dictates. The coolest part is you can make your own attributes. The following is a very simple attribute:

[AttributeUsage(AttributeTargets.Property)]
public class PropertyGroup : Attribute {

    private readonly string name;

    public PropertyGroup(string name) {
        this.name = name;
    }

    public string Name {
        get {
            return name;
        }
    }

}

It’s an attribute that can be attached to properties (AttributeTargets.Property). It requires a string name. This is how it can be used:

        ...

        [PropertyGroup("Settings")]
        public string Gender {
            get {
                return gender;
            }

            set {
                this.gender = value;
            }
        }

        [PropertyGroup("Settings")]
        public string Type {
            get {
                return type;
            }

            set {
                this.type = value;
            }
        }

        [PropertyGroup("OrientationIds")]
        public string DownSpriteId {
            get {
                return downSpriteId;
            }

            set {
                this.downSpriteId = value;
            }
        }

        [PropertyGroup("OrientationIds")]
        public string RightSpriteId {
            get {
                return rightSpriteId;
            }

            set {
                this.rightSpriteId = value;
            }
        }

        ...

We use PropertyGroup attribute as a grouping mechanism for our generic editor. What we do is in our editor code, we look for this attribute and collect such properties in their own container before rendering them. There are many ways to access an attribute through reflection. The following is one way:

public static T GetCustomAttribute<T>(PropertyInfo property) where T : Attribute {
    Attribute attribute = Attribute.GetCustomAttribute(property, typeof(T));
    return attribute as T;
}

// Usage
PropertyGroup group = GetCustomAttribute<PropertyGroup>(propertyInfo);

// Do something with the attribute like access its name
List<PropertyInfo> propertyList = GetPropertyList(group.Name);

With this, we can change the look of our editor by just adding attributes to our classes.

GroupedProperties

Other Uses

Persistence

In Part 2 of this series, I discussed an XML writer/reader by reading properties of classes. Aside from this, we also have a property attribute named Persist to selectively write/read properties with such attribute. The attribute also allows specification of a default value. We heavily use this attribute in our persistence system. This is useful for properties that are not present in old save files and you want a default value for them.

    [AttributeUsage(AttributeTargets.Property)]
    public class Persist : Attribute {

        private object defaultValue;

        public Persist() {
        }

        public Persist(object defaultValue) {
            this.defaultValue = defaultValue;
        }

        public object DefaultValue {
            get {
                return defaultValue;
            }
        }

    }

    // Sample usage
    [Persist]
    public float PolledTime {
        get {
            return polledTime;
        }

        set {
            this.polledTime = value;
        }
    }

    [Persist(1)]
    public int Day {
        get {
            return day;
        }

        set {
            this.day = value;
        }
    }

    [Persist(1)]
    public int Year {
        get {
            return year;
        }

        set {
            this.year = value;
        }
    }

    ...

Class Browser

In Part 1, I wrote about loading classes using their class names. As such, we have a lot of different editors where a user can select from a selection of different classes that derive from a single base class. The amount of classes written for these editors can get out of hand so we made a class level property to group classes into their respective domains.

    [AttributeUsage(AttributeTargets.Class)]
    public class Group : Attribute {

        private readonly string name;

        public Group(string name) {
            this.name = name;
        }

        public string Name {
            get {
                return name;
            }
        }

    }

    // Usage
    [Group("Game.CharacterNeeds")]
    public class AddNeedAmount : ComponentAction<CharacterNeeds> {
        ...
    }

    [Group("Game.Task")]
    class GetCurrentTaskEffortPerTile : ComponentAction<TaskDoer> {
    }

With this attribute, we can make our class browsers to look like this:

ClassBrowser

Conclusion

Reflection is a worthy tool to add to your gamedev toolbox. It’s powerful and useful. What I did in this series is probably just the tip of an iceberg. I’ve read about modders who opened up, ripped, and replaced game parts of C# games using reflection. Yikes!

I’m going to end the series for now. I may add to it later. I hope I have convinced you that reflection is a cool toy to learn.

Reflection Series – Part 2: Harnessing Properties

One of my favorite features in reflection is the ability to know about the properties of a certain instance at runtime. This has helped a lot in making tools to aid game development.

Basics

The following code is the simplest way to iterate through the properties of an instance:

// Let's say there's some instance named myInstance
Type type = typeof(myInstance);

// Get the properties that are public and not static
PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

foreach(PropertyInfo property in properties) {
    // Do something with property...
}

PropertyInfo contains the information about a property. You can get its getter and setter methods. You can invoke them. You can get its return type. You can query the attributes attached to the property. You will know a lot (just head over to its API reference).

Example Usage

One utility class that I’ve made is a generic XML writer and loader that can accept any instance and write the instance’s public properties to an XML. This way, I don’t have to make a custom XML writer code for each type of data. I can just use this class and tell it to write the instance.

I don’t write all public properties. I only select those with public getter and setter. The following is a utility method if such property is meant to be written:

public static bool IsVariableProperty(PropertyInfo property) {
    // should be writable and readable
    if(!(property.CanRead && property.CanWrite)) {
        return false;
    }

    // methods should be public
    MethodInfo getMethod = property.GetGetMethod(false);
    if(getMethod == null) {
        return false;
    }

    MethodInfo setMethod = property.GetSetMethod(false);
    if(setMethod == null) {
        return false;
    }

    return true;
}

This is how I built the writer class (showing only the important parts):

class InstanceWriter {

    private readonly Type type;
    private PropertyInfo[] properties;

    // A common delegate for writing a property of each type
    private delegate void PropertyWriter(XmlWriter writer, PropertyInfo property, object instance);
    private Dictionary<Type, PropertyWriter> attributeWriterMap = new Dictionary<Type, PropertyWriter>();

    // Constructor
    public InstanceWriter(Type type) {
        this.type = type;
        this.properties = this.type.GetProperties(BindingFlags.Public | BindingFlags.Instance); // Cached

        // Populate map of writers
        this.attributeWriterMap[typeof(string)] = WriteAsAttribute;
        this.attributeWriterMap[typeof(int)] = WriteAsAttribute;
        this.attributeWriterMap[typeof(float)] = WriteAsAttribute;
        this.attributeWriterMap[typeof(bool)] = WriteAsAttribute;
        // ... More types can be added here if needed
    }

    // Writes the specified instance to the writer
    public void Write(XmlWriter writer, object instance) {
        writer.WriteStartElement(this.type.Name);

        // Traverse properties
        foreach (PropertyInfo property in this.properties) {
            if (!TypeUtils.IsVariableProperty(property)) {
                // Not a candidate to be written
                continue;
            }

            // Must have a writer
            PropertyWriter propWriter = null;
            if (this.attributeWriterMap.TryGetValue(property.PropertyType, out propWriter)) {
                // Invokes the property writer
                propWriter(writer, property, instance);
            }
        }

        writer.WriteEndElement();
    }

    // Writer methods. There are more of these to support the types you need to support.
    private static void WriteAsAttribute(XmlWriter writer, PropertyInfo property, object instance) {
        // Invoking the getter using reflection
        object value = property.GetGetMethod().Invoke(instance, null);
        if (value != null) {
            writer.WriteAttributeString(property.Name, value.ToString());
        }
    }

}

This class just maintains a dictionary of writer methods mapped by Type. During traversal of properties, it checks if a property needs to be written and that it has a mapped writer method. PropertyInfo.PropertyType was used to get the type of the property. It then proceeds to invoke that writer method which writes the value to the XmlWriter.

The actual class is more elaborate than this. There’s a separate map for property writers that needs child elements. For example, Vector3 needs a child element and its xyz values are stored as attributes. We also took it further by checking if the property implements a custom interface of ours named IXmlSerializable and invokes the writer method of that property.

This is then how it is used:

InstanceWriter writer = new InstanceWriter(typeof(MyClass));
writer.Write(xmlWriter, myClassInstance); // Writes a whole element representing MyClass

My XmlLoader was made using the same concept only that the mapped methods now invoke the setter of the property. This is one of the loader methods:

private static void LoadString(SimpleXmlNode node, PropertyInfo property, object instance) {
    if(!node.HasAttribute(property.Name)) {
        // No value from XML. Set a default value.
        SetDefault(property, instance);
        return;
    }

    string value = node.GetAttribute(property.Name);
    property.GetSetMethod().Invoke(instance, new object[] { value });
}

Other Uses

I’ve made a generic data Unity editor that can support any type of data class as long as they expose the editable variables in the form of properties. As you can see in my other posts, most of our data editors have the same look. That’s because we are using the same base code for the editor and provide the custom rendering when necessary.

CharacterSpritesEditor
One of our generic data editors

In part 1 of this series where I talked about loading instances from mere string, we are also using properties manipulation to expose the variables of such instances in the editor. The following is a screenshot from our GOAP data editor.

GoapVariables

All of these are possible because of reflection.

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.