Quelle est la meilleure façon de cache coûteux données obtenues à partir de la réflexion? Par exemple, la plupart des fast-sérialiseurs cache ces informations de sorte qu'ils n'ont pas besoin de réfléchir à chaque fois qu'ils rencontrent le même type de nouveau. Ils peuvent même générer une dynamique de la méthode dont ils chercher de la type.
Avant de .net 4
Traditionnellement, j'ai utilisé un normal dictionnaire statique pour que. Par exemple:
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
}
}
Ceci apporte un peu de mémoire, mais comme il ne fait qu'une seule fois par Type et types vécu aussi longtemps que l' AppDomain
je ne pense pas que d'un problème.
Depuis .net 4
Mais maintenant .net 4 introduit à Collectionner les Assemblages de Type Dynamique de Génération. Si j'ai jamais utilisé, DoSomething
sur un objet déclaré dans les collectionner assemblée que l'assemblée ne sera jamais déchargé. Ouch.
Alors, quelle est la meilleure façon de cache par des informations de type dans .net 4 qui ne souffre pas de ce problème? La solution la plus simple je pense est de un:
private static ConcurrentDictionary<WeakReference, TCachedData> cache.
Mais l' IEqualityComparer<T>
j'aurais à utiliser avec celle-ci se comporte très étrangement, et que cela risquait de violer le contrat. Je ne suis pas sûr de la façon rapide de la recherche serait soit.
Une autre idée est d'utiliser une expiration de délai d'attente. Peut-être la solution la plus simple, mais se sent un peu inélégant.
Dans le cas où le type est fourni en paramètre générique je peux utiliser un imbriquée classe générique qui ne devrait pas souffrir de ce problème. Mais sa ne fonctionne pas si le type est fourni dans une 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.
}
}
Mise à jour: Une idée que je viens a l'aide d' Type.AssemblyQualifiedName
comme clé. Que doit identifier de manière unique ce type sans le garder en mémoire. Je pourrais même sortir avec l'aide d'identité référentielle sur cette chaîne.
Un problème qui reste avec cette solution est que la valeur mise en cache peut conserver une référence au type de trop. Et si j'utilise une référence faible pour qu'il sera très probablement expirer loin devant l'assemblée d'être déchargé. Et je ne suis pas sûr de comment pas cher il est normal de référence d'une référence faible. Semble que j'ai besoin de faire quelques tests et d'analyse comparative.