.NET Reflection, Boxing, and Properties in XNA games

jwatte's picture

System.Reflection is great! You can find all public properties on an object, and manipulate them programmatically, without knowing the exact type of the object. You can also treat properties generically, by passing a PropertyInfo and object instance around. This allows you to build generic animation systems (similar to how the Windows Presentation Foundation dynamic animatable properties work).

However, if you're animating value types, you will create a lot of garbage on the heap through boxing, because PropertyInfo.SetValue() goes through the object type, which causes things like Vector2 or float to get boxed.

To get around the boxing problem, you can declare container classes, and pre-allocate the container classes. It turns out that Nullable makes for a fine container class.

public class Foo {
  Vector2 myValueType_;
  Nullable<Vector2> myValueTypeWrapper_ = new Nullable<Vector2>();
  public Nullable<Vector2> PositionWrapper {
    set { myValueType_ = value.Value; }
    get { myValueTypeWrapper_.Value = myValueType_; return myValueTypeWrapper_; }  }
  public Vector2 Position { get { return myValueType_; } }
}

Now, on the setting side, you will need to keep a Nullable around as well, so you don't create a new one every time.
Pretty? No.

If you want to go one step further, you can define an IAnimatable interface, and expose that for each of your animatable properties. The interface will take care of shuffling values back and forth.

public interface IAnimatable<T> where T : struct{
  T GetValueAtTime(double time);  // you may or may not care about time
  void SetValueAtTime(T t, double time);
  string DisplayName { get; }
  Type Type { get; }
}

You can also create a concrete class that implements this interface, and takes an anonymous delegate for setters and getters:

public class Animatable<T> : IAnimatable<T> where T : struct
{
  public T GetValueAtTime(double time) { return getter_(time); }
  public void SetValueAtTime(T t, double time) { return setter_(time); }
  public string DisplayName { get { return name_; } }
  public Type Type { get { return typeof(T); } }
  public Animatable(GetterFunc<T> getter, SetterFund<T> setter, string name)
    {
      this.getter_ = getter;
      this.setter_ = setter;
      this.name_ = name;
    }
  GetterFunc<T> getter_;
  SetterFunc<T> setter_;
  string name_;
}
public delegate void SetterFunc<T>(T t, double time) where T : struct;
public delegate T GetterFunc<T>(double time) where T : struct;

Finally, you would use that in your class as such:

public class SomeEntity {
  Vector2 position_;
  Animatable<Vector2> positionProp_;
  public IAnimatable<Vector2> Position { get { return positionProp_; } }
  public SomeEntity() {
    positionProp_ = new Animatable<Vector2>(
        delegate (Vector2 v, double time) { position_ = v; },
        delegate (double time) { return position_; },
        "Position");
  }
}

Please excuse the generic delegate syntax, I may have gotten it slightly wrong, as this code is just typed in as an illustration.

Note that, at this point, you're building your own reflection system, without the generality of System.Reflection -- but then you have control, so that you can avoid the boxing.