我在c#中使用分布式系统并遇到障碍。
我需要能够使用类型
序列化谓词Predicate<ICollection<IEntity>> p = (entities => entities.OfType<Person>().Count() <= 3);
我相信这在.net中是不可能的,所以我的问题是,是否存在任何可以解决问题的框架。
我已经尝试了几个框架,但是继续遇到他们无法序列化带有集合或列表的谓词的问题
希望有人知道解决方案。几个星期以来一直坚持这个问题......
答案 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 可能是首选框架,特别是如果不仅要处理简单的谓词,还要处理更高级的查询(包括投影等)。