求助:使用Newtonsoft.Json.Linq与System.Linq.Dynamic.Core时SelectToken报错问题
解决Dynamic LINQ Core调用JToken.SelectToken时的解析异常问题
我之前也遇到过一模一样的问题,核心原因确实是Dynamic LINQ Core会优先把实现了IEnumerable的类型的方法识别为LINQ聚合/查询运算符,而JToken(包括JObject)正好实现了IEnumerable<JToken>,所以解析器错误地把SelectToken当成了LINQ聚合方法去查找,才抛出了"No applicable aggregate method"异常。
这里有几个比包装类更简洁的解决方案,完全能满足你表达式可存储、可UI配置的需求:
方案1:显式类型转换引导解析器
最简单的办法是在表达式字符串中,把参数显式转换为JToken类型,这样解析器就会优先查找该类型的实例方法,而不是把它当成IEnumerable处理。
修改后的代码示例:
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) { // 通过显式类型转换,让解析器正确识别JToken的实例方法 var exp = DynamicExpressionParser.ParseLambda( new ParameterExpression[] { Expression.Parameter(typeof(JToken), "jobj") }, typeof(JToken), "(jobj as Newtonsoft.Json.Linq.JToken).SelectToken(\"$\")"); // 验证执行效果 var compiledFunc = exp.Compile(); var result = compiledFunc.DynamicInvoke(json); Console.WriteLine(result?.ToString()); // 输出 {} } } }
方案2:配置解析器简化表达式
如果觉得表达式里写完整命名空间太繁琐,可以通过ParsingConfig添加命名空间引用,这样就能用简化的类型名来写表达式:
using Newtonsoft.Json.Linq; using System.Linq.Dynamic.Core; using System.Linq.Dynamic.Core.Configuration; using System.Linq.Expressions; namespace DynamicLinqCore { class Program { static JObject json = JObject.Parse(@"{}"); static void Main(string[] args) { var config = new ParsingConfig { // 允许通过简单类型名解析类型 ResolveTypesBySimpleName = true, // 添加Newtonsoft.Json.Linq命名空间到解析器的查找范围 CustomTypeProviders = new[] { new DefaultDynamicLinqTypeProvider { Namespaces = { "Newtonsoft.Json.Linq" } } } }; var exp = DynamicExpressionParser.ParseLambda( config, new ParameterExpression[] { Expression.Parameter(typeof(JToken), "jobj") }, typeof(JToken), "(jobj as JToken).SelectToken(\"$\")"); var result = exp.Compile().DynamicInvoke(json); Console.WriteLine(result); } } }
方案原理说明
Dynamic LINQ的解析逻辑中,当处理成员访问时,如果当前类型实现了IEnumerable,会先尝试匹配LINQ聚合方法;而通过显式类型转换后,解析器会先处理类型转换操作,得到明确的JToken类型,此时就会直接查找该类型的实例方法SelectToken,不会再把它当成LINQ运算符处理。
这两种方案都不需要额外的包装类,同时保持了表达式字符串的可存储性和UI配置友好性,完全符合你的需求。
内容的提问来源于stack exchange,提问作者Magnus
相关产品推荐
相关产品推荐

