我无法找到如何使用 Serialize.Linq 编译反序列化表达式的方法。 “使用 Serialize.Linq 在运行时编译表达式” 中接受的答案不起作用(下面的第 2 部分):
using System.Linq.Expressions;
using Serialize.Linq.Extensions;
using Serialize.Linq.Serializers;
namespace ConsoleApp3;
internal class Program {
static void Main() {
Expression<Func<double, double, double>> distanceCalc =
(x, y) => Math.Sqrt(x * x + y * y);
var xParameter = Expression.Parameter(typeof(double), "x");
var yParameter = Expression.Parameter(typeof(double), "y");
var xSquared = Expression.Multiply(xParameter, xParameter);
var ySquared = Expression.Multiply(yParameter, yParameter);
var sum = Expression.Add(xSquared, ySquared);
var sqrtMethod = typeof(Math).GetMethod("Sqrt", new[] { typeof(double) }) ?? throw new InvalidOperationException("Math.Sqrt not found!");
var distance = Expression.Call(sqrtMethod, sum);
var distanceLambda = Expression.Lambda<Func<double, double, double>>(
distance,
xParameter,
yParameter);
var serializer = new ExpressionSerializer(new Serialize.Linq.Serializers.JsonSerializer());
string serializedExpression = serializer.SerializeText(distanceLambda);
// part 1 works
var de1 = serializer.DeserializeText(serializedExpression).ToExpressionNode().ToExpression<Func<double, double, double>>();
var espre1 = de1.Compile();
Console.WriteLine(espre1(3, 4));
// part 2 as per "Compile Expression at runtime Using Serialize.Linq" doesn't work
var de2 = serializer.DeserializeText(serializedExpression) as LambdaExpression;
var espre2 = de2.Compile();
// Console.WriteLine(espre2(3, 4)); compiler error on espre2 "Method name expected"
// part 3 another problem
var de3 = serializer.DeserializeText(serializedExpression).ToExpressionNode().ToExpression<Func<double, double, double>>();
var t3 = de3.GetType();
var tm3 = t3.GetMethod("Compile", []);
var espre3 = tm3.Invoke(de3, []); // expre3 shows "Internal error evaluating expression" in debug
// Console.WriteLine(espre3(3, 4)); compiler error on espre3 "Method name expected"
}
}
当然,第 1 部分不是这样,因为“ToExpression
另外,请解释一下第3部分的问题。
鉴于您正在尝试处理不一定知道方法签名的一般情况,因此您只需将
LambdaExpression
编译为 Delegate
。
假设您有以下内容:
过程就是将函数反序列化为
LambdaExpression
,编译为Delegate
,然后调用Invoke
。不幸的是 Delegate
不允许直接调用,但您可以使用 Method
属性来访问已编译的方法,然后调用它。
与此类似的东西:
static object? ExecuteSerializedFunction(string serializedFunction, object?[] parameters)
{
ExpressionSerializer serializer = new(new JsonSerializer());
LambdaExpression? expression = serializer.DeserializeText(serializedFunction)
.ToExpressionNode()
as LambdaExpression;
// Compile to a Delegate with any signature
Delegate? function = expression?.Compile();
// Get the method to execute
MethodInfo? method = funcion?.Method;
// In my testing compilation adds a 'Capture' parameter - adjust as required.
object?[] actualParameters = [null, ..parameters]
// Execute the method and return the result.
// NB: There is no instance variable for the invocation.
return method?.Invoke(null, actualParameters);
}
这已经相当简单了,并且很有可能在所需的参数列表中出现意想不到的东西。我在上面的代码中添加了一个空的“Capture”参数,但您需要做的远不止于此。如果获取到错误的参数列表,
Invoke
会抛出异常。
(另外,处理异常。这只是一个最小的例子。)