I have these classes:
public class Entity
{
public static readonly EntitySchema Schema = new EntitySchema();
}
public abstract class BaseSchema
{
public abstract string Name {get;}
}
public class EntitySchema : BaseSchema
{
public override string Name => "Schema";
}
Now, I want to access EntitySchema.Name
from a method, which does not know anything about Entity (cannot access the static field).
I could do this with reflection:
static BaseSchema GetSchema<T>()
{
var pr = typeof(T).GetField("Schema");
var schema = pr.GetValue(null);
return schema as BaseSchema;
}
but compared to a direct call Entity.Schema.Name
the reflection version is 50x slower.
Is there a way to convert the reflection version into an Expression Tree and pre-compile the call?
Sure you can do that, but .NET requires to have the full field definition (EntitySchema global::Entity.Schema
in this case) to get the actual value. Reflection gets you this definition. You'd need to make a delegate for every type, ie:
public static class SchemaGetter
{
private static readonly Dictionary<object, Func<BaseSchema>> _lookup = new Dictionary<object, Func<BaseSchema>>();
public static BaseSchema Get<T>()
{
Func<BaseSchema> action;
if(!_lookup.TryGetValue(typeof(T), out action))
{
action = MakeDelegate<T>();
_lookup.Add(typeof(T), action);
}
return action();
}
private static Func<BaseSchema> MakeDelegate<T>()
{
// We did this before already...
FieldInfo field = typeof(T).GetField("Schema", BindingFlags.Public | BindingFlags.Static);
var fieldExpression = Expression.Field(null, field);
var lambda = Expression.Lambda<Func<BaseSchema>>(fieldExpression);
return lambda.Compile();
}
}
Followed by BaseSchema schema = SchemaGetter.Get<Entity>()
to get the actual schema.
Perhaps its sufficient enough to cache the result that you've got from your initial GetSchema<T>()
implementation (wrap it in a dictionary lookup). I think it must in this case, since the field is static anyway.