GetMethods 中反射的开销是多少

Posted

技术标签:

【中文标题】GetMethods 中反射的开销是多少【英文标题】:What is the overhead of reflection in GetMethods 【发布时间】:2011-05-17 02:27:23 【问题描述】:

我刚刚在我编写的几个解析器中重构了一段通用代码。 该代码用于自动发现方法实现,并且可以非常方便地扩展现有解析器或使用更多 DRY 代码(尤其是我一个人在这个项目上工作):

[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 ...)实现, 或者我是否应该在发现过程中使用缓存。 我真的不确定反射调用的效率如何。

【问题讨论】:

对不起,我想使用标签的自动完成,但我不知何故发布到早期 ^^ 而且我发现反射不是拼写反射^^ 您能否解释一下“可能频繁创建和销毁的类”的含义?您的意思是 DynamicCallableMethodTable&lt;TClass, THandle&gt; 实例通常是短暂的吗?既然类型对我来说似乎是不可变的,为什么不缓存它的实例呢? DynamicCallableMethodTable 也适用于实例方法(因此实例参数将是方法的实例,我将编辑示例 我不能使用调试器来处理常见的情况,因为它在很远的服务器中使用,所以我认为我不能真正有效地节省时间,我更希望能进入后面.NET 实现,如果已经有足够的缓存在进行,那么我不想重复缓存逻辑... 是的,它叫做 MemberInfo 缓存。更多信息在这里:msdn.microsoft.com/en-us/magazine/cc163759.aspx 【参考方案1】:

基于@Sergey的以下想法

是的,它被称为 MemberInfo 缓存。更多信息请点击此处:msdn.microsoft.com/en-us/magazine/cc163759.aspx – Sergey

我将静态代码提取到静态类中,它基于通用静态类字段将有自己的插槽的假设(即使它不使用通用参数?)。 虽然我不确定是否应该直接存储 MethodInfo。从长远来看,RuntimeMethodHandle 似乎可以节省空间。

static class ReflectionMethodCache<TClass>

    /// <summary>
    /// this field gets a different slot for every usage of this generic static class
    /// http://***.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;
    

【讨论】:

很好,可以阅读代码中的链接并链接它,太棒了! :) 静态泛型类的链接用途?

以上是关于GetMethods 中反射的开销是多少的主要内容,如果未能解决你的问题,请参考以下文章

java的反射机制之getDeclaredMethods和getMethods的区别

C#-反射知识点

EventBus的简单使用与原理

反射之Method如何获取字节码对象中的方法

corejava_反射

反射 基本应用