2008-11-03 9 views
15

Когда скомпилирован Expression<T>, возникает ли код, неявно кэшированный каркасом? Я думаю по строкам статических методов Regex, где структура неявно компилирует и кэширует последние несколько регулярных выражений.Когда компилируется выражение <T>, оно неявно кэшируется?

Если скомпилированные Expression<T> объекты не кэшируются, вы можете порекомендовать некоторые лучшие практики для поддержания времени компиляции вниз или каких-либо подводные камни, которые могут вызвать проблемы, если я вручную кэшировать выражение?

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

В этом примере, я немного обеспокоен тем, что, если я кэшировать скомпилированное выражение, что он будет использовать значение arg1 и arg2, как они были в то время выражение было составлено, а не получение этих значений из соответствующего места в стеке (т.е. вместо получения текущих значений).

ответ

10

Нет; Я не верю, что это так; если вы хотите его кэшировать, вы должны придерживаться ссылки Delegate (обычно Func<...> или Action<...>). Аналогично, если вы хотите получить максимальную производительность, вы должны скомпилировать его как параметризованное выражение, поэтому при его вызове вы можете отправлять разные значения.

В этом случае повторная фразировка поможет:

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

т.е. делает параметры числа выражения, и передать фактическим те, во время выполнения (вместо того, чтобы константы в выражении).

+1

Привет, Марк, я никогда не встречал таких оптимизаций. Можете ли вы сообщить, действительно ли это полезно с точки зрения производительности, кэширования предварительно скомпилированных запросов? – 2014-07-31 06:48:42

1

Lambda experssions не кэшируются автоматически. Для этого вам понадобится реализовать собственные алгоритмы кэширования/замещения. Проверьте, связанный StackOverflow вопрос:

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

Важно отметить, что лямбда-выражения ленивы оценены в C#.