Question

Lorsqu'un Expression < T > est compilé, le code résultant est-il implicitement mis en cache par le framework? Je pense aux méthodes Regex statiques, dans lesquelles le cadre compile et met en cache implicitement les dernières expressions rationnelles.

Si les objets Expression < T > compilés ne sont pas mis en cache, pouvez-vous recommander certaines des meilleures pratiques pour limiter le temps de compilation ou éviter les pièges risquant de poser problème mettre en 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 crains un peu que, si je cache l'expression compilée, les valeurs arg1 et arg2 soient utilisées telles qu'elles étaient à l'époque. l'expression a été compilée plutôt que de récupérer ces valeurs à l'emplacement approprié dans la pile (c'est-à-dire plutôt que d'obtenir les valeurs actuelles).

Était-ce utile?

La solution

Non; Je ne crois pas que ce soit le cas. si vous souhaitez 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 différentes valeurs lorsque vous l’appelez.

Dans ce cas, reformuler serait utile:

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

i.e. Définissez les paramètres numériques de l'expression et transmettez-les réels à l'exécution (plutôt que d'être constants dans l'expression).

Autres conseils

Les expressions Lambda ne sont pas mises en cache automatiquement. Pour cela, vous devrez implémenter vos propres algorithmes de mise en cache / mémorisation. Vérifiez la question Stackoverflow associée:

Est est-il possible de mettre en cache une valeur évaluée dans une expression lambda?

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top