I\'m doing a distributed system in c# and have encountered a barrier.
I need to be able to serialize Predicate with type
Predicate
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()
.