缓存反射数据 [英] Caching reflection data

查看:140
本文介绍了缓存反射数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是缓存来自反射获得昂贵的数据的最佳方式是什么?例如最快速的串行器缓存等信息,以便他们并不需要反映他们遇到的相同类型的再次每次。他们甚至可能会生成一个动态的方法,他们查找的类型。

What's the best way to cache expensive data obtained from reflection? For example most fast serializers cache such information so they don't need to reflect every time they encounter the same type again. They might even generate a dynamic method which they look up from the type.

传统上,我使用了普通的静态字典的。例如:

Traditionally I've used a normal static dictionary for that. For example:

private static ConcurrentDictionary<Type, Action<object>> cache;

public static DoSomething(object o)
{
    Action<object> action;
    if(cache.TryGetValue(o.GetType(), out action)) //Simple lookup, fast!
    {
        action(o);
    }
    else
    {
        // Do reflection to get the action
        // slow
    }
} 

这泄漏有点内存,但因为它只有一次,每个类别和种类住,只要的AppDomain 我不认为这是一个问题。

This leaks a bit of memory, but since it does that only once per Type and types lived as long as the AppDomain I didn't consider that a problem.

但现在.NET 4中引入庆功大会动态键入代。如果我用的DoSomething 在收藏集该程序集永远不会得到卸载声明的对象。哎哟。

But now .net 4 introduced Collectible Assemblies for Dynamic Type Generation. If I ever used DoSomething on an object declared in the collectible assembly that assembly won't ever get unloaded. Ouch.

那么什么是每个在.NET 4类型信息,不存在这个问题缓存的最佳方法是什么?我能想到的最简单的解决方案是:

So what's the best way to cache per type information in .net 4 that doesn't suffer from this problem? The easiest solution I can think of is a:

private static ConcurrentDictionary<WeakReference, TCachedData> cache.

的IEqualityComparer&LT; T&GT; 我不得不与使用会表现得非常奇怪,并可能会违反合同了。我不知道如何快速查找就两种。

But the IEqualityComparer<T> I'd have to use with that would behave very strangely and would probably violate the contract too. I'm not sure how fast the lookup would be either.

另一个想法是使用期满的超时。可能是最简单的解决方案,但感觉有点不雅。

Another idea is to use an expiration timeout. Might be the simplest solution, but feels a bit inelegant.

在其中类型被作为通用参数I可以使用哪些不应该存在这个问题嵌套一般类的情况下。但他如果该类型的变量提供不起作用。

In the cases where the type is supplied as generic parameter I can use a nested generic class which should not suffer from this problem. But his doesn't work if the type is supplied in a variable.

class MyReflection
{
    internal Cache<T>
    {
        internal static TData data;
    }

    void DoSomething<T>()
    {
        DoSomethingWithData(Cache<T>.data);
        //Obviously simplified, should have similar creation logic to the previous code.
    }
}


更新:一个想法我刚刚是用 Type.AssemblyQualifiedName 的关键。这应该唯一地标识该类型没有保持它在内存中。我甚至可能逃脱使用引用的身份在此字符串。


Update: One idea I've just had is using Type.AssemblyQualifiedName as the key. That should uniquely identify that type without keeping it in memory. I might even get away with using referential identity on this string.

这仍然与此解决方案的一个问题是,该高速缓存的值可能保持一个参考型太。如果我使用它很可能会到期为止,大会被卸载之前的弱引用。而且我不知道它是多么便宜,得到一个正常参考出来的弱引用。看来我需要做一些测试和基准。

One problem that remains with this solution is that the cached value might keep a reference to the type too. And if I use a weak reference for that it will most likely expire far before the assembly gets unloaded. And I'm not sure how cheap it is to Get a normal reference out of a weak reference. Looks like I need to do some testing and benchmarking.

推荐答案

ConcurrentDictionary&LT; WeakReference的,CachedData&GT; 不正确,在这种情况下。假设我们正在试图缓存类型T的信息,因此 WeakReference.Target == typeof运算(T)。 CachedData极有可能会包含引用的typeof(T)也。由于 ConcurrentDictionary&LT; TKEY的,TValue&GT; 节点&lt的内部集合店项目; TKEY的,TValue&GT; 你将不得不链强引用: ConcurrentDictionary 实例 - > 节点实例 - > 属性( CachedData )实例 - > 的typeof(T)。在一般情况下是不可能的,以避免内存泄漏的WeakReference的情况下,当值可能会引用他们的钥匙。

ConcurrentDictionary<WeakReference, CachedData> is incorrect in this case. Suppose we are trying to cache info for type T, so WeakReference.Target==typeof(T). CachedData most likely will contain reference for typeof(T) also. As ConcurrentDictionary<TKey, TValue> stores items in the internal collection of Node<TKey, TValue> you will have chain of strong references: ConcurrentDictionary instance -> Node instance -> Value property (CachedData instance) -> typeof(T). In general it is impossible to avoid memory leak with WeakReference in the case when Values could have references to their Keys.

有必要增加对 ephemerons 做出这样的场景可能没有内存泄漏。幸运的是.NET 4.0支持他们,我们必须 ConditionalWeakTable&LT; TKEY的,TValue&GT; 类。看来<一href="http://blogs.msdn.com/b/dotnet/archive/2009/05/18/the-conditional-weak-table-enabling-dynamic-object-properties.aspx">reasons引进它接近你的任务。

It was necessary to add support for ephemerons to make such scenario possible without memory leaks. Fortunately .NET 4.0 supports them and we have ConditionalWeakTable<TKey, TValue> class. It seems the reasons to introduce it are close to your task.

这个方法也解决了您的更新中提到的参考类型将完全生活,只要集加载的问题。

This approach also solves problem mentioned in your update as reference to Type will live exactly as long as Assembly is loaded.

这篇关于缓存反射数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆