Serialize expression tree

前端 未结 3 976
隐瞒了意图╮
隐瞒了意图╮ 2021-02-01 04:14

I\'m doing a distributed system in c# and have encountered a barrier.

I need to be able to serialize Predicate with type

Predicate

        
3条回答
  •  梦毁少年i
    2021-02-01 05:05

    I've attempted this before. It will take some work, but you can develop your own protocol to pass predicates across a network.

    First, you need to change the type of your p variable to an Expression so it can be deconstructed:

    Expression>> p = (entities => entities.OfType().Count() <= 3);
    
    VisitExpression(p);
    

    The C# compiler will see that you are assigning a lambda to an Expression variable, and it will actually build an expression tree for you.

    Now, you can walk the expression tree and serialize it to your custom protocol. I'll use a StringBuilder here, to create a JSON object (for easy deserialization).

    StringBuilder sb = new StringBuilder();
    
    void VisitExpression(Expression e)
    {
        switch (e.ExpressionType)
        {
        case ExpressionType.And:
            return VisitBinaryExpression(e As BinaryExpression);
    
        ...
        }
    }
    
    void VisitBinaryExpression(BinaryExpression e)
    {
        sb.AppendLine("{");
        switch (e.ExpressionType)
        {
        case ExpressionType.And:
            sb.Append("\"Type\": \"And\",");
            break;
    
        ...
        }
        sb.Append("\"Left\":");
        VisitExpression(e.Left); sb.Append(",");
        sb.Append("\"Right\":");
        VisitExpression(e.Right);
        sb.AppendLine("}");
    }
    

    Depending on how your distributed system handles collections and lists, you will need to implement the corresponding logic when walking the expression tree. I would start by using typeof(IEnumerable<>).MakeGenericType(typeof(IEntity)).IsAssignableFrom(typeToTest).

    When serializing, you will have to send the full names of the types, methods, and overloads across the network. You'll probably want to make sure that each compute node is referencing all the same libraries, so that you can correctly resolve the types and methods when you deserialize everything.

    When you finally deserialize, rebuild the expression tree on the remote host using the classes in the System.Linq.Expressions namespace. Then, compile and run the expression using Lambda.Compile().

提交回复
热议问题