2016-06-25 5 views
1

を経由して、ネストされたクラスから静的フィールドを取得します。私は、これらのクラス持つ式ツリー

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にアクセスしたいです。

私は反射でこれを行うことができます:

直接呼び出し Entity.Schema.Name反射バージョンに比べ
static BaseSchema GetSchema<T>() 
{ 
    var pr = typeof(T).GetField("Schema"); 
    var schema = pr.GetValue(null); 
    return schema as BaseSchema; 
} 

しかしが50倍遅くなります。

リフレクションバージョンをエクスプレッションツリーに変換し、コールをあらかじめコンパイルする方法はありますか?

答えて

2

確かにそうすることができますが、実際の値を取得するには、.NETに完全なフィールド定義(この場合はEntitySchema global::Entity.Schema)が必要です。反射はあなたにこの定義を与えます。あなたはすなわち、すべてのタイプのためのデリゲートを作成する必要があると思います。実際のスキーマを取得するためにBaseSchema schema = SchemaGetter.Get<Entity>()続く

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

おそらく、最初のGetSchema<T>()の実装から得た結果をキャッシュするのに十分な(辞書ルックアップでラップする)のに十分です。とにかくフィールドは静的なので、このケースではそうする必要があると思います。

+0

ありがとうございました! var f = MakeDelegate ()のコンパイル済みバージョンを実行すると、1250msではなく10mio呼び出しで約44msになりました! –

関連する問題