2010-11-29 3 views
3

Я просто переработал общую часть кода в нескольких парсерах, которые я написал. Код используется для автоматического обнаружения реализаций методы, и он приходит в очень удобно, чтобы расширить существующие парсер или использовать более DRY кода (особенно я работаю над этим проектом в одиночку):Что такое накладные расходы на отражение в 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

+0

Не могли бы вы уточнить, что вы подразумеваете под «класс, который может быть создан и часто уничтожались "? Вы имеете в виду, что 'DynamicCallableMethodTable ' экземпляры обычно недолговечны? Поскольку тип кажется мне неизменным, почему бы не кешировать его? – Ani

+0

DynamicCallableMethodTable также работает над методами экземпляра (поэтому параметр экземпляра будет экземпляром метода, я отредактирую для примера – Sebastian

ответ

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; 
    } 
} 
+0

Nice, SO может прочитать ссылку в коде и связать ее, как удивительно ! :) Связано Используется для статических родовых классов? – Sebastian

+0

, похоже, работает нормально – Sebastian

Смежные вопросы