我曾尝试过这样做。需要一些工作,但您可以开发自己的协议来在网络上传递谓词。
首先,您需要将变量 p
的类型更改为 Expression<TDelegate>
,以便对其进行分解:
Expression<Predicate<ICollection<IEntity>>> p = (entities => entities.OfType<Person>().Count() <= 3);
VisitExpression(p);
C#编译器会发现你将一个lambda分配给Expression<TDelegate>
变量,它实际上会为你构建一个表达式树。
现在,你可以遍历表达式树并将其序列化到你的自定义协议中。我将使用StringBuilder
在此处创建一个JSON对象(以便轻松反序列化)。
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("}");
}
根据您的分布式系统处理集合和列表的方式,您需要在遍历表达式树时实现相应的逻辑。我建议使用
typeof(IEnumerable<>).MakeGenericType(typeof(IEntity)).IsAssignableFrom(typeToTest)
开始。
在序列化时,您需要通过网络发送类型、方法和重载的完整名称。您可能需要确保每个计算节点都引用了所有相同的库,以便在反序列化时正确解析类型和方法。
最后,在远程主机上使用
System.Linq.Expressions
命名空间中的类重建表达式树。然后,使用
Lambda.Compile()
编译和运行表达式。
p
并不是一个表达式树,它只是一个匿名函数。它被编译成一个委托,指向一个生成的方法static bool SomeFunnyName(ICollection<IEntity> entities) { return entities.OfType<Person>().Count() <= 3; }
。 - Jeppe Stig Nielsen