Unity3D Reflections – Part 1

Those of you who are already familiar with managed languages might be familiar with reflections. Me, having a longer background in unmanaged programming languages, reflections as a concept are new and shiny. Reflections provide the ability for the program to examine and modify it’s own structure and behavior at runtime. In this post we are only going to be using a small portion of functionality provided by the C#’s System.Reflection library. Mainly, GetType()GetProperties() and SetValue(). Today, we are going to implement a simple way for injecting dependencies (properties in this case) to a child object (prefab). The example i’m using here is just an example. I tried to keep it as short as possible. In the example project we’re going to use dependency injection to pass parent object’s RigidBody component to a prefab which will apply acceleration force to that RigidBody component.

Unity Part

Let’s first create the Unity-editor stuff. We’ll need a 3D plane, a cube and an empty GameObject. Plane should have a collider by default, so no need to add anything. For the Cube, we’ll add a script named Cube.cs  and a RigidBody3D component. Rename the empty GameObject as Gravity, add Gravity.cs script and create a prefab out of it. Finally, add the newly created prefab under the Cube GameObject. The prefab part isn’t really necessary.
That’s all of the Unity-editor stuff done. Next up, the code.

C# Part

In the Cube.cs all we really have to do is to call the Injector.InjectPropert<T>() which will be covered in the last code snippet. We’ll give it the parent object to whose children we want to inject the given Component.
// Cube.cs
using UnityEngine;

public class Cube : MonoBehaviour 
{
  // Use this for initialization
  private void Awake() 
  {
    Injector.InjectProperty<Rigidbody>(
      this.gameObject, this.GetComponent<Rigidbody>());
  }
}
Next up is the code for the Gravity-prefab object. The important part is the public Rigidbody GravityRigidbody property. The rest of the code is just for demonstration purposes.
// Gravity.cs
using UnityEngine;

public class Gravity : MonoBehaviour 
{
  // This is the property we'll be setting 
  // with Injector.PropertyInject<>()
  public Rigidbody GravityRigidbody 
  {
    get; set;
  }

  public float gravityForce = -9.81f;

  private void FixedUpdate() 
  {
    // Just to be sure, check if GravityRigidbody was set. 
    if(GravityRigidbody != null) 
    {
      GravityRigidbody.AddForce(Vector3.up * gravityForce, 
          ForceMode.Acceleration);
    }
  }
}
Finally the most important part, Injector.cs. I decided to make it static and to keep it generic. We could define it under Cube.cs, but we might want to use it elsewhere. The most important parts of the code are the way we get the properties for Components (lines 19-21) and how we set the value for given Component (line 31)
// Injector.cs
using UnityEngine;

using System.Reflection;
using System.Linq;

public static class Injector 
{
  // Simple static injector
  public static void InjectProperty<T>(GameObject gameObject, T dependency) 
  {
    // Go through the child objects
    foreach(Transform child in gameObject.transform) 
    { 
      foreach(Component childComponent in child.gameObject.GetComponents()) 
      {
        // Using the power of LINQ to get the settable properties for 
        // the Components where we can read and write the value and 
        // is of type T
        var properties = childComponent.GetType().GetProperties().Where(
          prop => prop.CanRead && prop.CanWrite).Where(
            prop => prop.PropertyType == typeof(T));
        
        // If nothing of suitable type is foundt, properties variable
        // should be null
        if(properties != null) 
        {
          foreach(PropertyInfo pi in properties) 
          {
            // Use SetValue of System.Reflection.PropertyInfo to 
            // set the value of the property
            pi.SetValue(childComponent, (object)dependency, null);
          }
        }
      }
    }
  }
}
On the lines 19-21, what we’re doing is just getting all the properties from a Component under a child which can be written to and read from and are of type T (which is the RigidBody in our case).  If GetProperties() returns anything else than null, we know that we have a match. GetType() is quite straightforward. It returns the instance of Type class that contain information about the the object’s type. See Microsoft’s documentation for more information. We’re only interested about the GetProperties() method here. GetProperties() returns the list of properties. We’re using Liqn to go through the result. In line 31, we use System.Reflection.PropertyInfo.SetValue() to set the value of the property. Microsoft’s documentation defines SetValue as:
public virtual void SetValue (object obj, object value, object[] index);
  • obj – The object whose property value will be set
  • value – The new property value. Which in our case is the reference to Cube’s RigidBody
  • index – Optional index value. In our case this can be left as null. This is only used when dealing with indexed properties.

Limitations and problems

As you might have already noticed, the way we’re forcing the RigidBody to Cube’s children isn’t really that safe. We might have solved the coupling issue and made our lives a little bit easier, but at the same time we’re burdening ourselves with the notion that now we might have to handle disabling dependency injection for some parts of the code. What if two or more scripts wants to inject dependencies to the same child object? We’ll figure out ways to limit the Injector in some other post. GitHub link: https://github.com/jkelanne/Reflections-part_01