3

我想要完成的是检查 JSON 文档是否符合约束,如果符合则转换文档。另一个要求是约束是用户定义的,我需要将它们存储在文档数据库中。

我最初的想法是使用 JSON-path 来选择我想要测试的令牌。这被证明是不可能的,因为 JSON-path 没有兄弟姐妹或父母的概念。但是,如果我将 JSON-path 与来自 json.net 的 LINQ 结合起来,我可以使用 SelectToken 找到一个令牌,然后调用 Next 来获取我可以依次测试的兄弟姐妹。像这样的表达式还有一个额外的好处,即用户可以通过 UI 相对容易地进行配置,并且可以将其作为字符串存储在文档数据库中。

所以我尝试做一个 PoC 并立即遇到了一个我无法解决的大问题。下面的示例是该 PoC 的简化版本。我要做的是运行System.Linq.Dynamic.Core并查询Newtonsoft.Json.Linq.JObject。我可以访问属性,但是当我尝试使用 SelectToken 时出现异常。

如果我运行以下示例:

using Newtonsoft.Json.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;

namespace DynamicLinqCore
{
    class Program
    {

        static JObject json = JObject.Parse(@"{}");
        static void Main(string[] args)
        {
            var exp = DynamicExpressionParser.ParseLambda(new ParameterExpression[] {
                Expression.Parameter(typeof(JToken), "jobj")
            },           
            typeof(JToken),
            "jobj.SelectToken(\"$\")");            
        }
    }
}

我明白了:

System.Linq.Dynamic.Core.Exceptions.ParseException: 'No applicable aggregate method 'SelectToken(String)' exists'
Stack Trace:
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseAggregate(Expression instance, Type elementType, String methodName, Int32 errorPos, Boolean isQueryable) in C:\Users\Jonathan\Documents\GitHub\System.Linq.Dynamic.Core\src\System.Linq.Dynamic.Core\Parser\ExpressionParser.cs:line 1745
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParseMemberAccess(Type type, Expression instance) in C:\Users\Jonathan\Documents\GitHub\System.Linq.Dynamic.Core\src\System.Linq.Dynamic.Core\Parser\ExpressionParser.cs:line 1623
   at System.Linq.Dynamic.Core.Parser.ExpressionParser.ParsePrimary() in C:\Users\Jonathan\Documents\GitHub\System.Linq.Dynamic.Core\src\System.Linq.Dynamic.Core\Parser\ExpressionParser.cs:line 744

通过查看 System.Linq.Dynamic.Core 的代码,看起来,由于 JObject 实现了 IEnumerable,它不会尝试寻找方法。它只是假设它应该是一个 linq 运算符。我可以通过为实现 SelectToken 而不是接口 IEnumerable 的 JToken 实现一个包装类来绕过这一点。这是一个非常麻烦的解决方法,我真的不想这样做。

有没有其他人遇到过这个问题并且可以提供更好的解决方案或解决方法?

4

0 回答 0