如何编译带有参数操作的 MethodCallExpression?
How to compile MethodCallExpression with operations on arguments?
我有方法Method
private static int Method(int n)
{
return n;
}
我在我的 ExpressionVisitor 中重写了 VisitMethodCall 得到了 MethodCallExpression。 MethodCallExpression 包含:
n => Method(2 + n)
我想把它编译成 Func 并这样调用:
func(3)
而且应该 return 5.
我试过这个:
IEnumerable<ParameterExpression> parameters = expression.Arguments.Select(a => Expression.Parameter(a.Type, a.ToString()));
MethodCallExpression call = Expression.Call(expression.Method, parameters);
Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, call.Arguments.OfType<ParameterExpression>());
var func = lambda.Compile();
Console.WriteLine(func(3));
而且是 return 我 3,不是 5
因为2+x是param name,我用3代替了。
不确定你为什么要这样做,但无论如何要做到这一点你需要提取你的 MethodCallExpression
使用的参数(不是参数)。为此,您可以像这样滥用表达式访问者:
public class ParametersExtractorVisitor : ExpressionVisitor {
public IList<ParameterExpression> ExtractedParameters { get; } = new List<ParameterExpression>();
protected override Expression VisitParameter(ParameterExpression node) {
ExtractedParameters.Add(node);
return base.VisitParameter(node);
}
}
然后在您的代码中像这样使用它:
var visitor = new ParametersExtractorVisitor();
visitor.Visit(expression);
MethodCallExpression call = Expression.Call(expression.Method, expression.Arguments);
Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, visitor.ExtractedParameters);
var func = lambda.Compile();
Console.WriteLine(func(3));
你不需要访问者来实现它。
基本上你的 Method
函数应该提供传递给 lambda 的值的加法运算结果,常量值为 2.
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Test
{
class Program
{
static void Main(string[] args) {
var method = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.Public);
var parameter = Expression.Parameter(typeof(int), "n");
var add = Expression.Add(Expression.Constant(2, typeof(int)), parameter);
var methodCallExpression = Expression.Call(null, method, add);
var lambda = Expression.Lambda<Func<int, int>>(methodCallExpression, parameter);
var func = lambda.Compile();
Console.WriteLine(func(3));
}
public static int Method(int n) => n;
}
}
我会通过改变 MethodCallExpression 使用访问者来实现它
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Test
{
class MethodCallVisitor : ExpressionVisitor
{
private readonly int toAdd;
public MethodCallVisitor(int toAdd) {
this.toAdd = toAdd;
}
protected override Expression VisitMethodCall(MethodCallExpression node) {
var add = Expression.Add(node.Arguments.First(), Expression.Constant(toAdd));
return Expression.Call(node.Object, node.Method, add);
}
}
class Program
{
static void Main(string[] args) {
var methodCallVisitor = new MethodCallVisitor(2);
var method = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.Public);
var parameter = Expression.Parameter(typeof(int), "n");
var methodCallExpression = Expression.Call(null, method, parameter);
var lambda = Expression.Lambda<Func<int, int>>(methodCallExpression, parameter);
lambda = (Expression<Func<int, int>>)methodCallVisitor.Visit(lambda);
var func = lambda.Compile();
Console.WriteLine(func(3));
}
public static int Method(int n) => n;
}
}
我有方法Method
private static int Method(int n)
{
return n;
}
我在我的 ExpressionVisitor 中重写了 VisitMethodCall 得到了 MethodCallExpression。 MethodCallExpression 包含:
n => Method(2 + n)
我想把它编译成 Func 并这样调用:
func(3)
而且应该 return 5.
我试过这个:
IEnumerable<ParameterExpression> parameters = expression.Arguments.Select(a => Expression.Parameter(a.Type, a.ToString()));
MethodCallExpression call = Expression.Call(expression.Method, parameters);
Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, call.Arguments.OfType<ParameterExpression>());
var func = lambda.Compile();
Console.WriteLine(func(3));
而且是 return 我 3,不是 5
因为2+x是param name,我用3代替了。
不确定你为什么要这样做,但无论如何要做到这一点你需要提取你的 MethodCallExpression
使用的参数(不是参数)。为此,您可以像这样滥用表达式访问者:
public class ParametersExtractorVisitor : ExpressionVisitor {
public IList<ParameterExpression> ExtractedParameters { get; } = new List<ParameterExpression>();
protected override Expression VisitParameter(ParameterExpression node) {
ExtractedParameters.Add(node);
return base.VisitParameter(node);
}
}
然后在您的代码中像这样使用它:
var visitor = new ParametersExtractorVisitor();
visitor.Visit(expression);
MethodCallExpression call = Expression.Call(expression.Method, expression.Arguments);
Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, visitor.ExtractedParameters);
var func = lambda.Compile();
Console.WriteLine(func(3));
你不需要访问者来实现它。
基本上你的 Method
函数应该提供传递给 lambda 的值的加法运算结果,常量值为 2.
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace Test
{
class Program
{
static void Main(string[] args) {
var method = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.Public);
var parameter = Expression.Parameter(typeof(int), "n");
var add = Expression.Add(Expression.Constant(2, typeof(int)), parameter);
var methodCallExpression = Expression.Call(null, method, add);
var lambda = Expression.Lambda<Func<int, int>>(methodCallExpression, parameter);
var func = lambda.Compile();
Console.WriteLine(func(3));
}
public static int Method(int n) => n;
}
}
我会通过改变 MethodCallExpression 使用访问者来实现它
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Test
{
class MethodCallVisitor : ExpressionVisitor
{
private readonly int toAdd;
public MethodCallVisitor(int toAdd) {
this.toAdd = toAdd;
}
protected override Expression VisitMethodCall(MethodCallExpression node) {
var add = Expression.Add(node.Arguments.First(), Expression.Constant(toAdd));
return Expression.Call(node.Object, node.Method, add);
}
}
class Program
{
static void Main(string[] args) {
var methodCallVisitor = new MethodCallVisitor(2);
var method = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.Public);
var parameter = Expression.Parameter(typeof(int), "n");
var methodCallExpression = Expression.Call(null, method, parameter);
var lambda = Expression.Lambda<Func<int, int>>(methodCallExpression, parameter);
lambda = (Expression<Func<int, int>>)methodCallVisitor.Visit(lambda);
var func = lambda.Compile();
Console.WriteLine(func(3));
}
public static int Method(int n) => n;
}
}