在运行时使用 Serialize.Linq 编译表达式
Compile Expression at runtime Using Serialize.Linq
我正在尝试序列化和反序列化 Linq 查询。目前我正在使用 Serialize.Linq 通过 json 序列化和反序列化 Linq 查询。像这样:
public async Task StoreQuery<T>(string queriedTypeName, string queryName, Expression<Func<T, bool>> query, IEnumerable<T> results)
where T : class, IStorable
{
var expressionSerializer = new ExpressionSerializer(new Serialize.Linq.Serializers.JsonSerializer());
var queryJson = expressionSerializer.SerializeText(query);
await storage.AddQuery(queriedTypeName + ".queries", queryJson, ...);
//etc...
}
如果我知道查询表达式要操作的类型,我就能成功反序列化查询:
public static bool QueryWouldContain<T>(T storable, string queryJson)
where T : class, IStorable
{
var queryStatement = expressionSerializer.DeserializeText(queryJson);
var expressionType = queryStatement.ToExpressionNode().ToExpression<Func<T,bool>>().Compile();
var objectBelongsInQueryResults = expressionType.Invoke(obj)
return objectBelongsInQueryResults;
}
但是,在这种情况下,我希望能够在运行时而不是编译时检测到该类型:
public static async bool QueriesWouldContain<T>(IEnumerable<T> storables, List<string> queryStrings)
where T : class, IStorable
{
foreach (var querystring in queryStrings)
{
var expressionSerializer = new ExpressionSerializer(new JsonSerializer());
var queryStatement = expressionSerializer.DeserializeText(querystring);
var expression = queryStatement.ToExpressionNode().ToExpression<Func<?, bool>>().Compile();
foreach (var storable in storables)
{
if (isOfTypeMatchingQuery(storable, expression))
{
var result = expression.Invoke(storable);
if (result == false)
{
return false;
}
}
}
return true;
}
有什么方法可以从表达式中得到操作的类型吗?如果是这样,有没有办法将该表达式转换为 Func?
调用 ToExpression
时不必指定泛型类型。只是测试一下,如果它 returns 一个 LambdaExpression
.
public static async bool QueriesWouldContain<T>(IEnumerable<T> storables, List<string> queryStrings)
where T : class, IStorable
{
foreach (var querystring in queryStrings)
{
var expressionSerializer = new ExpressionSerializer(new JsonSerializer());
var queryStatement = expressionSerializer.DeserializeText(querystring);
var expression = queryStatement.ToExpressionNode().ToExpression();
if (!(expression is LambdaExpression lambdaExpression))
continue; // TODO: or throw
var d = lambdaExpression.Compile();
foreach (var storable in storables)
{
if (isOfTypeMatchingQuery(storable, d))
{
var result = (bool)d.Invoke(storable);
if (result == false)
{
return false;
}
}
}
return true;
}
}
这是我在@esskar 发布他的回答之前想到的丑陋之处:
...
var expressionNode = queryStatement.ToExpressionNode();
var funcType = typeof(Func<,>).MakeGenericType(new Type[] { type, typeof(bool) });
var method = typeof(ExpressionNode).GetMethods().First(meth => meth.GetGenericArguments().Any() && meth.Name == "ToExpression" && meth.GetParameters().Count() == 1);
var methodWithGenerics = method.MakeGenericMethod(funcType);
dynamic expressionUncompiled = methodWithGenerics.Invoke(expressionNode, new object[] { null });
var expression = expressionUncompiled.Compile();
不用说,他的回答更可取。
我正在尝试序列化和反序列化 Linq 查询。目前我正在使用 Serialize.Linq 通过 json 序列化和反序列化 Linq 查询。像这样:
public async Task StoreQuery<T>(string queriedTypeName, string queryName, Expression<Func<T, bool>> query, IEnumerable<T> results)
where T : class, IStorable
{
var expressionSerializer = new ExpressionSerializer(new Serialize.Linq.Serializers.JsonSerializer());
var queryJson = expressionSerializer.SerializeText(query);
await storage.AddQuery(queriedTypeName + ".queries", queryJson, ...);
//etc...
}
如果我知道查询表达式要操作的类型,我就能成功反序列化查询:
public static bool QueryWouldContain<T>(T storable, string queryJson)
where T : class, IStorable
{
var queryStatement = expressionSerializer.DeserializeText(queryJson);
var expressionType = queryStatement.ToExpressionNode().ToExpression<Func<T,bool>>().Compile();
var objectBelongsInQueryResults = expressionType.Invoke(obj)
return objectBelongsInQueryResults;
}
但是,在这种情况下,我希望能够在运行时而不是编译时检测到该类型:
public static async bool QueriesWouldContain<T>(IEnumerable<T> storables, List<string> queryStrings)
where T : class, IStorable
{
foreach (var querystring in queryStrings)
{
var expressionSerializer = new ExpressionSerializer(new JsonSerializer());
var queryStatement = expressionSerializer.DeserializeText(querystring);
var expression = queryStatement.ToExpressionNode().ToExpression<Func<?, bool>>().Compile();
foreach (var storable in storables)
{
if (isOfTypeMatchingQuery(storable, expression))
{
var result = expression.Invoke(storable);
if (result == false)
{
return false;
}
}
}
return true;
}
有什么方法可以从表达式中得到操作的类型吗?如果是这样,有没有办法将该表达式转换为 Func?
调用 ToExpression
时不必指定泛型类型。只是测试一下,如果它 returns 一个 LambdaExpression
.
public static async bool QueriesWouldContain<T>(IEnumerable<T> storables, List<string> queryStrings)
where T : class, IStorable
{
foreach (var querystring in queryStrings)
{
var expressionSerializer = new ExpressionSerializer(new JsonSerializer());
var queryStatement = expressionSerializer.DeserializeText(querystring);
var expression = queryStatement.ToExpressionNode().ToExpression();
if (!(expression is LambdaExpression lambdaExpression))
continue; // TODO: or throw
var d = lambdaExpression.Compile();
foreach (var storable in storables)
{
if (isOfTypeMatchingQuery(storable, d))
{
var result = (bool)d.Invoke(storable);
if (result == false)
{
return false;
}
}
}
return true;
}
}
这是我在@esskar 发布他的回答之前想到的丑陋之处:
...
var expressionNode = queryStatement.ToExpressionNode();
var funcType = typeof(Func<,>).MakeGenericType(new Type[] { type, typeof(bool) });
var method = typeof(ExpressionNode).GetMethods().First(meth => meth.GetGenericArguments().Any() && meth.Name == "ToExpression" && meth.GetParameters().Count() == 1);
var methodWithGenerics = method.MakeGenericMethod(funcType);
dynamic expressionUncompiled = methodWithGenerics.Invoke(expressionNode, new object[] { null });
var expression = expressionUncompiled.Compile();
不用说,他的回答更可取。