4

I am attempting to Serialize and Deserialize Linq queries. Currently I am using Serialize.Linq to serialize and deserialize Linq queries via json. Like so:

    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...
    }

I am able to successfully deserialize the query if I know the type upon which the query expression is to operate:

    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;
    }

However I would like to be able to detect that type at runtime rather than compile time in cases like this:

    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;
        }

Is there any way to get from an expression what type is being operated on? and If so, Is there a way to convert that expression into a Func?

2 Answers 2

4

You don't have to specify the generic type when calling ToExpression. Just test, if it returns an 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;
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the help! You can see my answer below for how bad things were going...
Hello @esskar ! I'm having some difficulties using your library in a complex system. But my need is quite the same as the author of this question, so I was wondering that perhaps you could help me to solve my issue ? Here is the question link, thanks in advance ! stackoverflow.com/questions/75122222/…
2

Here is the ugliness I came up with before @esskar posted his answer:

...
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();

needless to say, his answer is far preferable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.