2008-11-03 8 views
15

Cuando se compila Expression<T>, ¿el código resultante está caché implícitamente en el marco? Estoy pensando en las líneas de los métodos estáticos Regex donde el marco implícitamente compila y almacena en caché las últimas expresiones regulares.Cuando se compila una Expresión <T>, ¿está en caché implícita?

Si compilados Expression<T> objetos son no en caché, puede recomendar algunos mejores prácticas para mantener el tiempo de compilación abajo o cualquier trampas que podrían causar problemas si cacheamos manualmente una expresión?

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

En este ejemplo, estoy un poco preocupado de que si cacheamos la expresión compilado, que utilizará los valores de arg1 y arg2 ya que estaban en ese momento se compiló la expresión, en lugar de recuperar esos valores desde el lugar apropiado en la pila (es decir, en lugar de obtener los valores actuales).

Respuesta

10

No; No creo que sea así; si lo quiere en caché, debe conservar la referencia Delegate (normalmente Func<...> o Action<...>). Del mismo modo, si desea obtener el mejor rendimiento, lo compilaría como una expresión parametrizada, para que pueda enviar diferentes valores cuando lo invoque.

En este caso, refraseo ayudaría:

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

es decir, hacer que los parámetros número de la expresión, y pasar los reales los que en tiempo de ejecución (en lugar de ser constantes en la expresión).

+1

Hola Mark, nunca he conocido este tipo de optimizaciones. ¿Puede indicar si esto es realmente útil en términos de rendimiento, almacenamiento en caché de consultas precompiladas? –

1

Las ampliaciones de Lambda no se guardan en caché automáticamente. Tendrá que implementar sus propios algoritmos de caché/memorando para eso. Compruebe la cuestión Stackoverflow relacionados:

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

Es importante señalar que las expresiones lambda son perezosos evaluado en C#.

Cuestiones relacionadas