通过表达式树从嵌套类中获取静态字段

时间:2016-06-25 10:04:32

标签: c# reflection lambda expression-trees

我有这些课程:

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";
}

现在,我想从一个方法访问EntitySchema.Name,该方法对实体一无所知(无法访问静态字段)。

我可以用反射做到这一点:

static BaseSchema GetSchema<T>()
{
    var pr = typeof(T).GetField("Schema");
    var schema = pr.GetValue(null);
    return schema as BaseSchema;
}

但与直接通话Entity.Schema.Name相比,反射版本慢了50倍

有没有办法将反射版本转换为表达式树并预编译调用?

1 个答案:

答案 0 :(得分:2)

当然可以这样做,但.NET需要具有完整的字段定义(在本例中为EntitySchema global::Entity.Schema)才能获得实际值。反思可以为您提供此定义。您需要为每种类型创建一个委托,即:

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();
    }
}

后面跟BaseSchema schema = SchemaGetter.Get<Entity>()获取实际架构。

也许它足以缓存您从初始GetSchema<T>()实现中获得的结果(将其包装在字典查找中)。我认为在这种情况下必须这样,因为无论如何这个领域都是静态的。