序列化表达式树

时间:2014-04-23 19:22:46

标签: c# serialization lambda expression-trees

我在c#中使用分布式系统并遇到障碍。

我需要能够使用类型

序列化谓词
Predicate<ICollection<IEntity>> p = (entities => entities.OfType<Person>().Count() <= 3);

我相信这在.net中是不可能的,所以我的问题是,是否存在任何可以解决问题的框架。

我已经尝试了几个框架,但是继续遇到他们无法序列化带有集合或列表的谓词的问题

希望有人知道解决方案。几个星期以来一直坚持这个问题......

3 个答案:

答案 0 :(得分:12)

我的解决方案:

将问题搁置了很长时间后,终于设法使用json.net和Aq.ExpressionJsonSerializer(https://github.com/aquilae/expression-json-serializer)解决了我的问题

public class JsonNetAdapter : IOconSerializer
{
    private readonly JsonSerializerSettings _settings;

    public JsonNetAdapter(JsonSerializerSettings settings = null)
    {
        var defaultSettings = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Objects};
        defaultSettings.Converters.Add(new ExpressionJsonConverter(Assembly.GetAssembly(typeof(IOconSituation))));
        _settings = settings ?? defaultSettings;
    }

    public string Serialize<T>(T obj)
    {
        return JsonConvert.SerializeObject(obj, _settings);
    }

    public T Deserialize<T>(string json)
    {
        return JsonConvert.DeserializeObject<T>(json, _settings);
    }
}

像魅力一样!

答案 1 :(得分:6)

我之前尝试过这个。这需要一些工作,但您可以开发自己的协议来通过网络传递谓词。

首先,您需要将p变量的类型更改为Expression<TDelegate>,以便对其进行解构:

Expression<Predicate<ICollection<IEntity>>> p = (entities => entities.OfType<Person>().Count() <= 3);

VisitExpression(p);

C#编译器会看到你正在为一个Expression<TDelegate>变量分配一个lambda,它实际上会为你构建一个表达式树。

现在,您可以遍历表达式树并将其序列化为自定义协议。我将在这里使用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()编译并运行表达式。

答案 2 :(得分:1)

Remote.Linq 可能是首选框架,特别是如果不仅要处理简单的谓词,还要处理更高级的查询(包括投影等)。