Когда выражение<T> компилируется, кэшируется ли оно неявно?
-
06-07-2019 - |
Вопрос
Когда Expression<T>
скомпилирован ли результирующий код неявно кэшируется фреймворком?Я думаю о статике Regex
методы, в которых фреймворк неявно компилирует и кэширует последние несколько регулярных выражений.
Если скомпилирован 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
такими, какими они были на момент компиляции выражения, вместо того, чтобы извлекать эти значения из соответствующего места в стеке (т.е.вместо того, чтобы получать текущие значения).
Решение
НЕТ;Я не верю, что это так;если вы хотите, чтобы он был кэширован, вы должны придерживаться 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;
}
т. е.сделайте числа параметрами выражения и передайте фактический использует его во время выполнения (вместо того, чтобы быть константами в выражении).
Другие советы
Лямбда-эксперименты не кэшируются автоматически. Для этого вам нужно будет реализовать собственные алгоритмы кэширования / запоминания. Проверьте связанный вопрос Stackoverflow:
Is можно кэшировать значение, вычисленное в лямбда-выражении?
Важно отметить, что лямбда-выражения лениво вычисляются в C #.