【发布时间】:2015-12-14 22:09:29
【问题描述】:
我正在做 Func -> Expression -> Func 转换。如果我从方法(下面的第一个示例)创建 Func() 它工作正常但是如果我使用表达式树创建函数(第二个示例)它在访问 时失败并出现 NullReferenceException >func2.Method.DeclaringType.FullName。这是因为 DeclaringType 为空。 (NJection 使用反射,所以我认为这就是它需要 DeclaringType 的原因。)
如何为通过编译表达式树创建的 Func 填写 DeclaringType 类型? (也许不可能?)DeclaringType 在第一个示例中设置。
从方法中使用 Func...(效果很好)
// Build a Func<>
Func<int, int> add = Add;
// Convert it to an Expression using NJection Library
Expression<Func<int, int>> expr = ToExpr<Func<int, int>>(add);
// Convert it back to a Func<>
Func < int, int> func = expr.Compile();
// Run the Func<>
int result = func(100);
使用表达式树(不起作用)...
// Build a Func<> using an Expression Tree
ParameterExpression numParam = Expression.Parameter(typeof(int));
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numAddFive = Expression.Add(numParam, five);
Func<int, int> func2 =
Expression.Lambda<Func<int, int>>(
numAddFive,
new ParameterExpression[] { numParam }).Compile();
// Convert to an Expression using NJection (EXCEPTION ON NEXT LINE)
// ToExpr is trying to access func2.Method.DeclaringType.FullName(DeclaringType is null)
Expression<Func<int, int>> exp2 = ToExpr<Func<int, int>>(func2);
// Convert it back to a Func<>
Func<int, int> func2b = exp2.Compile();
// Run the Func<>
int result2 = func2b(100);
【问题讨论】:
-
你想用
ToExpr<Func<int, int>>(func2)达到什么目的?你期待什么样的Expression回来? -
我还在学习 linq/labda/etc。我的目标是简化表达式表达式程序(或树)。也许我可以让编译器将表达式编译为代码,然后获取该代码并将其转换回表达式树。我猜想得到的表达式树将是原始的简化版本。因此,如果我有一个 a+a+a+2+4+3 的表达式树,那么我编译它并将该代码转换回我会得到 (3*a)+9 的表达式。 (我猜)我说的是 Func -> Expr -> Fun,但真正的目标是 Expr -> Func(code) -> Expr。如果我能做到第一个,那么我想我可以做到后一个。
-
为什么要简化表达式?如果您只是在之后编译并运行,编译器仍然会对其进行所有优化,所以不要打扰。如果您尝试使用编译器为您简化其他任务的表达式 - 您可能不会取得太大成就,因为您对“简单”的想法可能与编译器的想法完全不同。
-
两个原因:这是一个科学项目。 =) 我计划生成随机函数,然后稍微修改这些函数以创建一个新函数。加班会有很多垃圾,并且可以不时地进行简化以保持这些垃圾干净,因此希望编译得更快。 (类似于遗传算法)第二个原因是,如果有一种方法可以使用 C# 编译器的优化能力来简化任何块表达式,那就太好了!
-
您知道,C# 编译器几乎没有优化。主要部分由 JIT 完成(即在将 IL 转换为本机代码期间),因此像 NJection 这样的库对您没有帮助......
标签: c# lambda expression-trees linq-expressions