diff --git a/README.md b/README.md index 02a5c60..cd0bca0 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,18 @@ By default `LambdaParser` uses `ValueComparer` for values comparison. You can pr var valComparer = new ValueComparer() { NullComparison = ValueComparer.NullComparisonMode.Sql }; var lambdaParser = new LambdaParser(valComparer); ``` +### Caching Expressions + +The `UseCache` property determines whether the `LambdaParser` should cache parsed expressions. By default, `UseCache` is set to `true`, meaning expressions are cached to improve performance for repeated evaluations of the same expression. + +Therefore, using a singleton instance of `LambdaParser` is recommended, rather than creating a new instance each time. + +You can disable caching by setting UseCache to false if you want to save memory, especially when evaluating a large number of unique expressions. + +```csharp +var lambdaParser = new LambdaParser(); +lambdaParser.UseCache = false; +``` ## Who is using this? NReco.LambdaParser is in production use at [SeekTable.com](https://www.seektable.com/) and [PivotData microservice](https://www.nrecosite.com/pivotdata_service.aspx) (used for user-defined calculated cube members: formulas, custom formatting). diff --git a/src/NReco.LambdaParser/Linq/LambdaParser.cs b/src/NReco.LambdaParser/Linq/LambdaParser.cs index 9c3bedb..48e5561 100644 --- a/src/NReco.LambdaParser/Linq/LambdaParser.cs +++ b/src/NReco.LambdaParser/Linq/LambdaParser.cs @@ -13,6 +13,7 @@ #endregion using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; @@ -36,9 +37,8 @@ public class LambdaParser { static readonly string[] mulOps = new[] {"*", "/", "%" }; static readonly string[] addOps = new[] { "+", "-" }; static readonly string[] eqOps = new[] { "==", "!=", "<", ">", "<=", ">=" }; - - readonly IDictionary CachedExpressions = new Dictionary(); - readonly object _lock = new object(); + + readonly IDictionary CachedExpressions = new ConcurrentDictionary(); /// /// Gets or sets whether LambdaParser should use the cache for parsed expressions. @@ -124,9 +124,7 @@ public object Eval(string expr, IDictionary vars) { public object Eval(string expr, Func getVarValue) { CompiledExpression compiledExpr = null; if (UseCache) { - lock (_lock) { - CachedExpressions.TryGetValue(expr, out compiledExpr); - } + CachedExpressions.TryGetValue(expr, out compiledExpr); } if (compiledExpr == null) { @@ -136,11 +134,9 @@ public object Eval(string expr, Func getVarValue) { }; var lambdaExpr = Expression.Lambda(linqExpr, compiledExpr.Parameters); compiledExpr.Lambda = lambdaExpr.Compile(); - + if (UseCache) - lock (_lock) { - CachedExpressions[expr] = compiledExpr; - } + CachedExpressions[expr] = compiledExpr; } var valuesList = new List();