C# JSON属性名称作为属性的整个JSON路径

C# JSON属性名称作为属性的整个JSON路径,c#,json,.net,json.net,C#,Json,.net,Json.net,我希望每个JSON属性名都代表它的路径 public class Person { public string FirstName { get; set; } public string LastName { get; set; } public Address Address { get; set; } } public class Address { public string Street { get; set; } public string S

我希望每个JSON属性名都代表它的路径

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string StreetNumber { get; set; }
}
使用Newtonsoft.Json,我当前获得以下Json:

{
   "firstName":"Homer",
   "lastName":"Simpson",
   "address":{
      "street":"Evergreen Terrace",
      "streetNumber":"742"
   }
}
是否可以改为获取此JSON:

{
   "person.firstName":"Homer",
   "person.lastName":"Simpson",
   "person.address":{
      "person.address.street":"Evergreen Terrace",
      "person.address.streetNumber":"742"
   }
}

你不能那样做,因为这是模棱两可的。如何反序列化此文件

在C#中,它可以解释为

公共类人物
{
公共字符串Person.firstName{get;set;}
公共字符串Person.LastName{get;set;}
公共广播人员.地址{get;set;}
}
它的格式无效,因此您的文件必须导致异常或编译错误


在浏览器上使用
JSON.parse()
方法尝试此操作,您将得到一个具有此结构的对象(属性名称带有点)。

此格式无效。但是: 样品


Json.NET不会使用JSONPATH作为开箱即用的属性名来序列化对象,因为它是基于约定的序列化程序。因此,它将以在序列化图中遇到的相同方式序列化某些类型的所有实例。相反,对于遇到的每个实例,您需要一个稍微不同的契约,该契约反映了图中实例的路径

那么,获取所需JSON的选项是什么

首先,您可以使用
公共静态无效重命名(此JToken标记,字符串newName)
扩展方法将其从序列化到后处理:

后来:

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
Func<string, int, string, string> map = (name, depth, parentPath) => "person." + parentPath;
using var textWriter = new StringWriter();
using (var jsonWriter = new NameRemappingJsonWriter(textWriter, map) { Formatting = Formatting.Indented })
{
    JsonSerializer.CreateDefault(settings).Serialize(jsonWriter, person);
}
var json = textWriter.ToString();
var设置=新的JsonSerializerSettings
{
ContractResolver=新的CamelCasePropertyNamesContractResolver(),
};
Func map=(名称、深度、父路径)=>“个人”+parentPath;
使用var textWriter=new StringWriter();
使用(var jsonWriter=newnameremappingjsonwriter(textWriter,map){Formatting=Formatting.Indented})
{
CreateDefault(设置).Serialize(jsonWriter,person);
}
var json=textWriter.ToString();
请注意,为了实现这一点,我必须调用基类
JsonWriter.WritePropertyName()
方法的基,该方法略显粗略和简单


Demo fiddle#2.

之后需要对JSON进行后处理。Json.NET是一个基于契约的序列化程序,因此,如果图中出现多个
Address
对象,它将使用相同的契约以相同的方式序列化它们。对于图形中出现的每个
Address
,您都需要不同的合同(因为属性名称不同)。序列化到
JObject
,然后修复属性名似乎是一条可行之路。这回答了你的问题吗?
            var p = new Person() { Address = new Address() { Street = "1", StreetNumber = "2" }, FirstName = "a", LastName = "b" };
        var x = _getCustomJsonFormat(p);
var person = new Person
{
    // Initialize your Person as required
};

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
var jObject = JObject.FromObject(person, JsonSerializer.CreateDefault(settings));
foreach (var item in jObject.Descendants().OfType<JProperty>().Select(p => (Property: p, p.Path)).ToList())
{
    // The Rename extension method from https://stackoverflow.com/a/47269811/3744182
    item.Property.Rename("person." + item.Path);
}

var json = jObject.ToString();
public class NameRemappingJsonWriter : JsonTextWriter
{
    readonly Action<string> jsonWriterWritePropertyName;
    readonly Func<string, int, string, string> map;

    public NameRemappingJsonWriter(TextWriter textWriter, Func<string, int, string, string> map) : base(textWriter)
    {
        this.map = map ?? throw new ArgumentNullException(nameof(map));
        //Method to call a base-of-base-class method taken from this answer https://stackoverflow.com/a/32562464
        //By https://stackoverflow.com/users/5311735/evk
        //To https://stackoverflow.com/questions/2323401/how-to-call-base-base-method
        var ptr = typeof(JsonWriter).GetMethod("WritePropertyName", new[] { typeof(string) }).MethodHandle.GetFunctionPointer();
        jsonWriterWritePropertyName = (Action<string>)Activator.CreateInstance(typeof(Action<string>), this, ptr);
    }

    public override void WritePropertyName(string name) => WritePropertyName(name, true);

    public override void WritePropertyName(string name, bool escape)
    {
        jsonWriterWritePropertyName(name);
        WriteRaw(JsonConvert.ToString(map(name, Top, Path)));
        WriteRaw(":");
    }       
}
var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
};
Func<string, int, string, string> map = (name, depth, parentPath) => "person." + parentPath;
using var textWriter = new StringWriter();
using (var jsonWriter = new NameRemappingJsonWriter(textWriter, map) { Formatting = Formatting.Indented })
{
    JsonSerializer.CreateDefault(settings).Serialize(jsonWriter, person);
}
var json = textWriter.ToString();