Когда компилируется выражение <T>, оно неявно кэшируется?
Когда скомпилирован Expression<T>
, результирующий код неявно кэшируется каркасом? Я думаю о строках статических методов Regex
, где структура неявно компилирует и кэширует последние несколько регулярных выражений.
Если скомпилированные Expression<T>
объекты являются not кэшированными, можете ли вы рекомендовать некоторые рекомендации по сохранению времени компиляции или любых ошибок, которые могут вызвать проблемы, если я вручную кэширую выражение?
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
, как они были в то время, когда выражение было скомпилировано, вместо того, чтобы извлекать эти значения из соответствующего места в стеке (т.е. вместо получения текущих значений).
Ответы
Ответ 1
Нет; Я не верю, что это так; если вы хотите его кешировать, вы должны придерживаться ссылки 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;
}
то есть. введите параметры номера выражения и передайте фактические значения во время выполнения (а не как константы в выражении).
Ответ 2
Lambda experssions не кэшируются автоматически. Для этого вам понадобится реализовать собственные алгоритмы кэширования/замещения. Проверьте связанный с этим вопрос Stackoverflow:
Возможно ли кэшировать значение, оцениваемое в выражении лямбда?
Важно отметить, что лямбда-выражения ленивы оцениваются в С#.