Quando un'espressione < T > è compilato, è implicitamente memorizzato nella cache?
-
06-07-2019 - |
Domanda
Quando viene compilata un'espressione < T >
, il codice risultante viene implicitamente memorizzato nella cache dal framework? Sto pensando secondo i metodi statici Regex
in cui il framework compila e memorizza in modo implicito gli ultimi regex.
Se gli oggetti compilati Expression < T >
non sono non memorizzati nella cache, puoi consigliare alcune best practice per ridurre i tempi di compilazione o eventuali gotcha che potrebbero causare problemi se memorizzare manualmente un'espressione nella cache?
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;
}
In questo esempio, sono leggermente preoccupato che se memorizzo nella cache l'espressione compilata, che utilizzerà i valori di arg1
e arg2
come erano al momento l'espressione è stata compilata, anziché recuperare quei valori dalla posizione appropriata nello stack (ovvero anziché ottenere i valori correnti).
Soluzione
No; Non credo che lo sia; se vuoi che sia memorizzato nella cache, devi tenere il riferimento Delegate
(in genere Func < ... >
o Action < ... >
). Allo stesso modo, se si desidera ottenere le migliori prestazioni, è necessario compilarlo come un'espressione parametrizzata, in modo da poter inviare valori diversi quando viene richiamato.
In questo caso, la riformulazione aiuterebbe:
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;
}
vale a dire. imposta i parametri numerici dell'espressione e passa quelli effettivi al momento dell'esecuzione (anziché essere costanti nell'espressione).
Altri suggerimenti
Le espansioni Lambda non vengono memorizzate automaticamente nella cache. Per questo dovrai implementare i tuoi algoritmi di memorizzazione nella cache / memoizzazione. Controlla la relativa domanda StackOverflow:
Is è possibile memorizzare nella cache un valore valutato in un'espressione lambda?
È importante notare che le espressioni lambda sono valutate in modo pigro in C #.