2010-11-29 38 views
3

我只是在我編寫的幾個解析器中重構了一段常見的代碼。 的代碼來自動發現方法的實現和它有非常方便擴展現有的解析器或(單獨尤其是我在做這個項目)使用更加乾燥代碼:GetMethods反射的開銷是什麼

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 
public class CallableAttribute : Attribute 
{ 
    public CallableAttribute() 
     : this(true) 
    { 
     // intentionally blank 
    } 

    private CallableAttribute(bool isCallable) 
    { 
     Callable = isCallable; 
    } 

    public bool Callable { get; private set; } 
} 

public class DynamicCallableMethodTable<TClass, THandle> 
    where THandle : class 
{ 
    private readonly IDictionary<string, THandle> _table = new Dictionary<string, THandle>(); 

    public DynamicCallableMethodTable(TClass instance, Func<string, string> nameMangler, 
          BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance) 
    { 
     var attributeType = typeof(CallableAttribute); 
     var classType = typeof(TClass); 

     var callableMethods = from methodInfo in classType.GetMethods(bindingFlags) 
           from CallableAttribute a in methodInfo.GetCustomAttributes(attributeType, false) 
           where a.Callable 
           select methodInfo; 

     foreach (var method in callableMethods) 
      _table[nameMangler(method.Name)] = method.CastToDelegate<THandle>(instance); 
    } 

    public bool TryGetMethod(string key, out THandle handle) 
    { 
     return _table.TryGetValue(key, out handle); 
    } 
} 

public static class MethodEx 
{ 
    public static TDelegate CastToDelegate<TDelegate>(this MethodInfo method, object receiver) 
     where TDelegate : class 
    { 
     return Delegate.CreateDelegate(typeof(TDelegate), receiver, method, true) as TDelegate; 
    } 
} 

現在我想用這個代碼在一個類可能被創建和銷燬頻繁:

class ClassWhichUsesDiscoveryOnInstanceMethodAndIsShortLived 
{ 
    private DynamicCallableMethodTable<string, TSomeDelegate> _table = ... 
    public ClassWhichUsesDiscoveryOnInstanceMethodAndIsShortLived() 
    { 
     _table = new DynamicCallableMethodTable<string, TSomeDelegate>(this, ...); 
    } 
} 

,所以我在徘徊中的getMethods的開銷,如果已經有在.NET裏面的一些緩存(4.0可用於...)實現, 或者我應該使用緩存進行發現過程。 我真的不確定反射調用的效率如何。

+0

對不起,我想利用標籤的自動補全,但不知何故,我貼到早期^^我也發現了反思是不是拼寫反射^^ – Sebastian 2010-11-29 04:55:03

+0

你能澄清你的「,這可能會創建類的意思並經常摧毀「?你的意思是說`DynamicCallableMethodTable `實例通常是短命的?由於類型對我來說是不可變的,爲什麼不緩存它的實例呢? – Ani 2010-11-29 05:05:51

回答

0

基於@Sergey

以下想法

是的,這就是所謂的MemberInfo緩存。更多關於它的位置:msdn.microsoft.com/en-us/magazine/cc163759.aspx - 謝爾蓋

我拿出靜態代碼到一個靜態類,其基於的假設是一個通用的靜態類領域將有自己的插槽(即使它不使用泛型參數?)。 儘管我不確定我是否不應直接存儲MethodInfo。 RuntimeMethodHandle似乎長期保存空間。

static class ReflectionMethodCache<TClass> 
{ 
    /// <summary> 
    /// this field gets a different slot for every usage of this generic static class 
    /// http://stackoverflow.com/questions/2685046/uses-for-static-generic-classes 
    /// </summary> 
    private static readonly ConcurrentDictionary<BindingFlags, IList<RuntimeMethodHandle>> MethodHandles; 

    static ReflectionMethodCache() 
    { 
     MethodHandles = new ConcurrentDictionary<BindingFlags, IList<RuntimeMethodHandle>>(2, 5); 
    } 

    public static IEnumerable<RuntimeMethodHandle> GetCallableMethods(BindingFlags bindingFlags) 
    { 
     return MethodHandles.GetOrAdd(bindingFlags, RuntimeMethodHandles); 
    } 

    public static List<RuntimeMethodHandle> RuntimeMethodHandles(BindingFlags bindingFlags) 
    { 
     return (from methodInfo in typeof (TClass).GetMethods(bindingFlags) 
       from CallableAttribute a in 
        methodInfo.GetCustomAttributes(typeof (CallableAttribute), false) 
       where a.Callable 
       select methodInfo.MethodHandle).ToList(); 
    } 
} 

public class DynamicCallableMethodTable<TClass, THandle> 
    where THandle : class 
{ 
    private readonly IDictionary<string, THandle> _table = new Dictionary<string, THandle>(); 

    public DynamicCallableMethodTable(TClass instance, Func<string, string> nameMangler, 
          BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance) 
    { 
     var callableMethods = ReflectionMethodCache<TClass>.GetCallableMethods(bindingFlags); 

     foreach (MethodInfo methodInfo in callableMethods.Select(MethodBase.GetMethodFromHandle)) 
     { 
      _table[nameMangler(methodInfo.Name)] = methodInfo.CastToDelegate<THandle>(instance); 
     } 
    } 

    public bool TryGetMethod(string key, out THandle handle) 
    { 
     return _table.TryGetValue(key, out handle); 
    } 
} 

public static class MethodEx 
{ 
    public static TDelegate CastToDelegate<TDelegate>(this MethodInfo method, object receiver) 
     where TDelegate : class 
    { 
     return Delegate.CreateDelegate(typeof(TDelegate), receiver, method, true) as TDelegate; 
    } 
} 
相關問題