- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个 gridview,我们可以在其中按不同的标准进行过滤。每个条件都是一个表达式。我有一个场景,在调用 Compile 方法时,我可以有超过一千个条件导致我的表达式抛出 StackOverflow。
顺便说一句,我在使用表达式树方面还是个初学者。
这是我为重现 stackoverflow 所做的示例。
var param = Expression.Parameter(typeof(SomeEntity), "SomeEntity");
Expression finalExpression = Expression.Default(typeof(bool));
for (int i = 0; i < 20000; i++) // Create 20000 expressions
{
var left = Expression.Property(param, "OrderID");
var right = Expression.Constant(42.ToString());
var expression = BinaryExpression.Equal(left, right);
finalExpression = Expression.OrElse(finalExpression, expression);
}
var hello = Expression.Lambda(finalExpression, param);
hello.Compile();
我的问题是:有没有办法“减少”这个表达式或任何其他防止计算溢出的解决方案?
谢谢
注意:下面是调试器中的表达式:
(SomeEntity.OrderID == "42"))
OrElse (SomeEntity.OrderID == "42"))
OrElse (SomeEntity.OrderID == "42"))
OrElse (SomeEntity.OrderID == "42"))
OrElse (SomeEntity.OrderID == "42"))
x20000
最佳答案
我刚刚成功地测试了此代码多达 1,000,000 个条件而没有堆栈溢出 - 我怀疑它可以处理您想要的任意数量的条件。
当在 lambda 表达式上调用 Compile
时,表达式树将递归地向下遍历以编译它;极深的树(像这样)需要很多很多的堆栈帧来完成 - 因此 StackOverflowException
。
我在下面所做的是在编译表达式并将其推送到已生成的条件集合之前,最多只接受固定数量的条件(由 MaxPredicateConditionCount
设置) .如果预生成表达式的集合达到最大值,则将它们组合成一个新表达式,依此类推。这样我们就可以限制编译表达式所需的递归深度(通过分段进行)。
public class PredicateBuilder<TParameter>
{
private const int MaxPredicateConditionCount = 500;
private readonly List<Expression<Func<TParameter, bool>>> _existingPredicates = new List<Expression<Func<TParameter, bool>>>(MaxPredicateConditionCount);
private readonly ParameterExpression _parameter = Expression.Parameter(typeof(TParameter));
private Expression<Func<TParameter, bool>> _expression;
private Expression _workingPredicate;
private int _workingPredicateConditionCount;
public bool Built { get; private set; }
public Expression<Func<TParameter, bool>> LambdaExpression
{
get
{
if (!Built)
{
return null;
}
return _expression;
}
}
public void AddCondition<TValue>(string propertyName, TValue value)
{
if (Built)
{
throw new InvalidOperationException("Predicate has already been built");
}
var property = Expression.Property(_parameter, propertyName);
var constant = Expression.Constant(value, typeof(TValue));
var equality = Expression.Equal(property, constant);
if (_workingPredicate == null)
{
_workingPredicate = equality;
}
else
{
if (MaxPredicateConditionCount < ++_workingPredicateConditionCount)
{
var compiledWorking = Expression.Lambda<Func<TParameter, bool>>(_workingPredicate, _parameter).Compile();
_existingPredicates.Add(p => compiledWorking(p));
if (_existingPredicates.Count + 1 > MaxPredicateConditionCount)
{
var compiled = BuildExistingPredicates().Compile();
_existingPredicates.Clear();
_existingPredicates.Add(p => compiled(p));
}
_workingPredicate = equality;
_workingPredicateConditionCount = 0;
}
else
{
_workingPredicate = Expression.OrElse(_workingPredicate, equality);
}
}
}
private Expression<Func<TParameter, bool>> BuildExistingPredicates()
{
Expression compileTemp = Expression.Invoke(_existingPredicates[0], _parameter);
for (var i = 1; i < _existingPredicates.Count; ++i)
{
var nextCall = Expression.Invoke(_existingPredicates[i], _parameter);
compileTemp = Expression.OrElse(compileTemp, nextCall);
}
return Expression.Lambda<Func<TParameter, bool>>(compileTemp, _parameter);
}
public void Build()
{
Built = true;
//There were no conditions, assume true
if (_workingPredicate == null)
{
_expression = x => true;
return;
}
_existingPredicates.Add(Expression.Lambda<Func<TParameter, bool>>(_workingPredicate, _parameter));
_expression = BuildExistingPredicates();
_existingPredicates.Clear();
_workingPredicate = null;
_workingPredicateConditionCount = 0;
}
public Func<TParameter, bool> Compile()
{
if (!Built)
{
Build();
}
return _expression.Compile();
}
}
示例实体
public class SomeEntity
{
public string OrderID { get; set; }
}
用法
class Program
{
static void Main()
{
var builder = new PredicateBuilder<SomeEntity>();
for (int i = 0; i < 1000000; i++) // Create 1,000,000 expressions
{
builder.AddCondition("OrderID", "42");
Console.Title = i.ToString();
}
builder.Compile();
}
}
关于c# - ExpressionTree Compile() 方法生成 stackoverflow 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14144510/
我在运行 compile test:compile it:compile经常并且...希望将击键次数减少到类似 *:compile 的数量。 .不过,它似乎不起作用。 $ sbt *:compile
有人可以给我这个问题的提示(或整个解决方案!): 在 Clojurescript 项目中,如何自动将编译日期/时间硬编码在符号中,以便在使用应用程序时显示? 谢谢。 最佳答案 有多种解决方案: 使用l
我是 ember.js 框架的新手,使用 ruby on rails 和 ember.debug.js -v 1.10.1(最新版本)。我一直在网上看到 ember 更改了这个最新的补丁,但我不知
我不是 Fortran 程序员(只是短暂的经验),但我需要编译一个部分用 F77 编写的程序。在我之前有人用 Absoft 编译器编译过它,但现在我需要在另一台机器上用 g77 重复这个过程。对于 A
我运行命令 mvn clean package 我得到了上面的错误我的 pom 是: http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0
我有以下问题。 我想在测试编译阶段排除一些.java文件(** / jsfunit / *。java),另一方面,我想在编译阶段包括它们(id我使用tomcat启动tomcat:运行目标) ) 我的p
符合 wikipedia A compiler is a computer program (or set of programs) that transforms source code writt
我想构建项目,但出现如下错误: 无法执行目标 org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile
当我通过右键单击项目名称进行 Maven 安装时,出现以下错误: [INFO] Scanning for projects... [WARNING] [WARNING] Some proble
我是 Maven 的新手,我想将我的应用程序导入到 Maven。和以前一样,我想将我的 ejb 项目中的类引用到我的 war 项目中。我在类中没有错误,但是如果我在我的父项目上安装 maven,那么我
当我将 ASP.NET Web 应用程序部署到生产环境时,我使用配置转换来删除 debug="true"来自 .但是,就在今天,我注意到 web.config 中的另一个部分如下所示:
This question already has answers here: Maven Compilation Error: (use -source 7 or higher to enable
我正在使用 Maven 3.0.5 和 Spring Tool Source 3.2 并安装了 Maven 插件。当我尝试执行“运行方式---> Maven 安装”时,出现以下错误: [INFO] S
我试图用 AngularJS 创建我自己的递归指令,它调用自己以漂亮的 JSON 格式转换 View 中的对象。好吧,首先我使用 ng-include 调用带有模板的脚本,在其中使用 ng-if 验证
可以通过 @suppress annotation使用Google的Closure Compiler在每个文件的基础上禁止显示警告。但是,似乎无法同时抑制多个警告-例如globalThis和check
假设一个拥有 10 到 20 年经验的熟练开发人员从未构建过编译器或模拟器,哪一个会更具挑战性? 你能比较一下会成为障碍的问题吗? 谢谢。 最佳答案 仿真和编译是完全不同的,但由于两者都被认为是“低级
最近发现Vim中有一个命令叫compiler。您可以使用任何常见的编译器(例如,:compiler gcc、:compiler php 等)来调用它,但它似乎没有任何立竿见影的效果。 我在联机帮助页上
我试图从 spring.io 指南中部署最简单的应用程序 Guide 但是我有一些麻烦.. 我做了什么: 创建的项目。 (来自 spring.io 教程) 下载 heroku CLI 在 Intell
每当进行 Maven Build..>clean install 时,我都会遇到此错误。我尝试过使用不同版本的插件并添加 testFailureIgnore 属性,但问题仍然存在。请找到下面的 POM
我有一个 web 应用程序,我尝试使用 maven 进行编译,不幸的是,在执行 mvn clean package 时它不起作用。 stackoverflow 上有很多问题看起来都一样,但没有解决了我
我是一名优秀的程序员,十分优秀!