2008-11-03 10 views
15

Lorsqu'un Expression<T> est compilé, le code résultant est-il implicitement mis en cache par le framework? Je pense aux méthodes statiques Regex où le framework compile implicitement et met en cache les dernières regex.Lorsqu'une Expression <T> est compilée, est-elle implicitement mise en cache?

Si compilé Expression<T> objets sont pas mises en cache, pouvez-vous recommander quelques bonnes pratiques pour garder la compilation vers le bas ou tout gotchas qui pourrait causer des problèmes si je cache manuellement une expression?

public MyResultType DoSomething(int arg1, int arg2) 
{ 
    var result = invokeHandler(
     (IDoSomethingHandler h) => h.DoSomething(arg1, arg2) 
    ); 
    return result; 
} 

private TResult invokeHandler<T, TResult>(Expression<Func<T, TResult>> action) 
    where T : class 
{ 
    // Here, I might want to check to see if action is already cached. 

    var compiledAction = action.Compile(); 
    var methodCallExpr = action as MethodCallExpression; 

    // Here, I might want to store methodCallExpr in a cache somewhere. 

    var handler = ServiceLocator.Current.GetInstance<T>(); 
    var result = compiledAction(handler); 

    return result; 
} 

Dans cet exemple, je suis un peu inquiet que si je en cache l'expression compilé, qu'il utilisera les valeurs de arg1 et arg2 comme ils étaient au moment où l'expression a été compilé, plutôt que de récupérer ces valeurs à partir de l'endroit approprié dans la pile (c'est-à-dire plutôt que d'obtenir les valeurs actuelles).

Répondre

10

Non; Je ne le crois pas; Si vous voulez le mettre en cache, vous devez conserver la référence Delegate (généralement Func<...> ou Action<...>). De même, si vous souhaitez obtenir les meilleures performances, vous devez le compiler en tant qu'expression paramétrée, de sorte que vous puissiez envoyer des valeurs différentes lorsque vous l'appelez.

Dans ce cas, re-phrasé pourrait aider:

public MyResultType DoSomething(int arg1, int arg2) 
{ 
    var result = invokeHandler(
     (IDoSomethingHandler h, int a1, int a2) => h.DoSomething(a1, a2), 
     arg1, arg2); 
    return result; 
} 

private TResult invokeHandler<T, TResult>(Expression<Func<T,int,int,TResult>> action, 
    int arg1, int arg2) 
    where T : class 
{ 
    // Here, I might want to check to see if action is already cached. 

    var compiledAction = action.Compile(); 
    var methodCallExpr = action as MethodCallExpression; 

    // Here, I might want to store methodCallExpr in a cache somewhere. 

    var handler = ServiceLocator.Current.GetInstance<T>(); 
    var result = compiledAction(handler, arg1, arg2); 

    return result; 
} 

à savoir faire les numéros des paramètres de l'expression, et de transmettre les réels ceux lors de l'exécution (plutôt que d'être constantes dans l'expression).

+1

Salut Mark, je n'ai jamais rencontré ce genre d'optimisations. Pouvez-vous s'il vous plaît aviser si cela est vraiment utile en termes de performance, de mise en cache des requêtes précompilées? –

1

Les expansions Lambda ne sont pas automatiquement mises en mémoire cache. Vous devrez implémenter vos propres algorithmes de mise en cache/mémo pour cela. Vérifiez la question Stackoverflow concernant:

Is it possible to cache a value evaluated in a lambda expression?

Il est important de noter que les expressions lambda sont paresseux évalués en C#.