首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linq表达式中的JsonPointer

Linq表达式中的JsonPointer
EN

Stack Overflow用户
提问于 2021-11-08 16:13:42
回答 2查看 255关注 0票数 0

是否有一种方法可以获得给定Linq.Expression的Linq.Expression,因为它将由给定的Newtonsoft.Json合同解析器序列化?

例如:

代码语言:javascript
复制
public class Foo { public string Bar { get; set; } }
var path = GetJsonPointer<Foo>(x => x.Bar, new CamelCasePropertyNamesContractResolver())
//how to write GetJsonPointer so that "path" would equal "/bar"?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-11-10 07:56:28

这里最棘手的部分是获取要序列化的属性的名称。您可以通过以下方式这样做:

代码语言:javascript
复制
static string GetNameUnderContract(IContractResolver resolver, MemberInfo member)
{
    var contract = (JsonObjectContract)resolver.ResolveContract(member.DeclaringType);
    var property = contract.Properties.Single(x => x.UnderlyingName == member.Name);
    return property.PropertyName;
}

一旦有了它,您就可以处理表达式的每个级别,并将结果弹出到字符串堆栈中。除了简单的成员访问之外,下面的快速和脏实现还支持索引。

代码语言:javascript
复制
public string GetJsonPointer<T>(IContractResolver resolver, Expression<Func<T,object>> expression)
{
    Stack<string> pathParts = new();

    var currentExpression = expression.Body;
    while (currentExpression is not ParameterExpression)
    {
        if (currentExpression is MemberExpression memberExpression)
        {
            // Member access: fetch serialized name and pop
            pathParts.Push(GetNameUnderContract(memberExpression.Member));
            currentExpression = memberExpression.Expression;
        }
        else if (
            currentExpression is BinaryExpression binaryExpression and { NodeType: ExpressionType.ArrayIndex }
            && binaryExpression.Right is ConstantExpression arrayIndexConstantExpression
        )
        {
            // Array index
            pathParts.Push(arrayIndexConstantExpression.Value.ToString());
            currentExpression = binaryExpression.Left;
        }
        else if (
            currentExpression is MethodCallExpression callExpression and { Arguments: { Count: 1 }, Method: { Name: "get_Item" } }
            && callExpression.Arguments[0] is ConstantExpression listIndexConstantExpression and { Type: { Name: nameof(System.Int32) } }
            && callExpression.Method.DeclaringType.GetInterfaces().Any(i=>i. IsGenericType && i.GetGenericTypeDefinition()==typeof(IReadOnlyList<>))
        )
        {
            // IReadOnlyList index of other type
            pathParts.Push(listIndexConstantExpression.Value);
            currentExpression = callExpression.Object;
        }
        else
        {
            throw new InvalidOperationException($"{currentExpression.GetType().Name} (at {currentExpression}) not supported");
        }
    }

    return string.Join("/", pathParts);
}

调用实例:

代码语言:javascript
复制
public record Foo([property: JsonProperty("Barrrs")] Bar[] Bars);
public record Bar(string Baz);

var resolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() };
GetJsonPointer<Foo>(resolver, x => x.Bars[0].Baz).Dump();
//dumps "/Barrrs[0]/baz"
票数 1
EN

Stack Overflow用户

发布于 2021-11-08 18:07:12

编辑:

对于json指针,请查看JsonPointer.Net。它是新套件的一部分,在System.Text.Json上运行。

因为你想要一个指针,所以使用Newtonsoft并不重要。使用linq生成指针,调用.ToString(),然后使用Newtonsoft来使用结果。

代码语言:javascript
复制
// get a pointer
var pointer = JsonPointer.Create<Foo>(x => x.Bar);
var asString = pointer.ToString();

// use the pointer

它现在不支持定制的套管,它使用的是模型的外壳。但是,这是一个很好的特性想法,我可以简单地添加。它将使用System.Text.Json机制而不是Newtonsoft。

有关更多信息,请参见医生们

对于json路径:

看看Manatee.Json。它绝对可以做到。

这是我json-所有套房的前身。

现在对我的新库已经不再推荐了,但是我还没有在新库中添加这个特性。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69886612

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档