d--b
d--b

Reputation: 5779

Is it possible to cache Reflection accessor to backing fields for optimization?

Accessing properties through reflection can lead to significant code reduction for things like ORM, but it usually is fairly slow. When these properties are auto-generated, the backing fields are always in the same position in the struct, and so theoretically, one could access them quickly. In C, you would just cache the offset to the right field in the struct, and call classpointer + fieldoffset. Is there any way (safe or not) to call Reflection to get that offset and cache it, and once we get it to access the content of the field?

I am thinking of something like this (please forgive my poor knowledge of unsafe syntax):

public class Data {
    public double Number { get; set; }
}

public class DataAccessor {
    private static Dictionary<string,int> _offsets;

    public static object Access(Data obj, string field) {
        int offset;
        if (!_offsets.TryGetValue(field, out offset)) {
            offset = typeof(Data).GetBackingFieldOffset(field);
            _offsets[field] = offset;
        }
        object content;
        unsafe {
            fixed(Data* p = obj) {
                content = *(obj + offset);
            }
        }
        return content;
    }

Upvotes: 1

Views: 504

Answers (1)

Sam Harwell
Sam Harwell

Reputation: 99859

It's certainly possible to cache a field accessor obtained through reflection. We use it extensively in StringTemplate 4 to optimize the rendering pipeline. The following code shows the way we generate an accessor delegate for accessing a field:

private static System.Func<object, object> BuildAccessor(FieldInfo field)
{
  ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
  UnaryExpression instance = !field.IsStatic ? Expression.Convert(obj, field.DeclaringType) : null;
  Expression<System.Func<object, object>> expr = Expression.Lambda<System.Func<object, object>>(
    Expression.Convert(
      Expression.Field(instance, field),
      typeof(object)),
    obj);

  return expr.Compile();
}

Reference: ObjectModelAdaptor

Upvotes: 5

Related Questions