使用 Serialize.Linq 编译反序列化表达式

问题描述 投票:0回答:1

我无法找到如何使用 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部分的问题。

c# serialization linq-expressions
1个回答
0
投票

鉴于您正在尝试处理不一定知道方法签名的一般情况,因此您只需将

LambdaExpression
编译为
Delegate

假设您有以下内容:

  • 函数序列化为 JSON。
  • 要传递到函数中的参数的对象数组。

过程就是将函数反序列化为

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
会抛出异常。

(另外,处理异常。这只是一个最小的例子。)

© www.soinside.com 2019 - 2024. All rights reserved.