gpt4 book ai didi

c# - 有选择地将实例的属性序列化为 JSON

转载 作者:太空宇宙 更新时间:2023-11-03 12:27:16 25 4
gpt4 key购买 nike

我有一些包含某种奇怪格式的 JSON 文件。我必须为我的项目阅读、修改和保存这种格式。不幸的是,我对给定的格式没有任何影响。

这种格式的奇怪之处在于,这种结构中的所有实体都有一个唯一的标识符,它被(无效地)称为“$id”。这些实例也可以通过它们的 id 而不是它们的完整属性集来引用。在这种情况下,没有“$id”,而是有一个“$ref”字段,其中包含一个已定义的实体。请看下面的(缩短的)示例:

{
"$id": "1",
"StyleName": "Standard",
"Style": {
"$id": "2",
"ShapeStyle": {
"$id": "3",
"Background": {
"$id": "4",
"Color": {
"$id": "5",
"A": 255,
"R": 68,
"G": 84,
"B": 106
}
}
},
"RightEndCapsStyle": {
"$id": "6",
"Background": {
"$id": "7",
"Color": {
"$ref": "5"
}
}
}
}
}

为了处理这个问题,我为所有 JSON 数据类创建了一个 C# 基类 Entity。这个基类维护一个 id 注册表,因此它可以轻松找到给定 $ref 的实例。这是代码:

public class Entity
{
public static Dictionary<string, Entity> Registry = new Dictionary<string, Entity>();

private string key = string.Empty;

[JsonProperty("$id", Order = -2)]
[DefaultValue("")]
public string Key
{
get { return key; }
set
{
key = value;
if (!string.IsNullOrEmpty(key)) Registry.Add(key, this);
}
}

[JsonProperty("$ref")]
public string RefKey { get; set; }

[JsonIgnore]
public bool IsReference => !string.IsNullOrEmpty(RefKey);

[JsonIgnore]
public Entity RefEntity
{
get
{
Entity entity = null;
if (IsReference && !Registry.TryGetValue(RefKey, out entity))
{
throw new ApplicationException("Referenced entity not found!");
}
return entity;
}
}
}

JSON 类层次结构如下所示:

public class RootObject: Entity
{
public string StyleName { get; set; }
public StyleRoot Style { get; set; }
}

public class StyleRoot: Entity
{
public Style ShapeStyle { get; set; }
public Style RightEndCapsStyle { get; set; }
}

public class Style: Entity
{
public Background Background { get; set; }
}

public class Background: Entity
{
public Color Color { get; set; }
}

public class Color: Entity
{
public int A { get; set; }
public int R { get; set; }
public int G { get; set; }
public int B { get; set; }
}

到目前为止,还不错。现在回答我的问题:

  1. [JsonProperty("$id")][JsonProperty("$ref")] 不起作用,因为 $id$ref 不是有效的 JSON 字段名称标识符。目前,我正在使用正则表达式将它们替换为有效的东西,然后将它们重新替换回原来的样子。但这是缓慢的。我想知道我是否可以使用 NamingStrategy 来实现相同的目的。但我没有成功。请记住,我需要两种方式,反序列化和序列化。
  2. 序列化是一个更难的问题。如果我按原样序列化我的结构,我最终会在每个实例中都有 "$id":"$ref": 字段。更重要的是,连同引用的项目,所有其他字段都使用默认值进行序列化。最简单的方法是在 JsonSerializerSettings 中简单地设置 DefaultValueHandling.IgnoreAndPopulate。但是通过这种方式,所有默认值都从输出中剥离,从而导致意外行为。我尝试使用 ContractResolver 但失败了,因为这是当前属性的本地属性,无法考虑周围的实体。有没有其他方法可以实现自定义序列化策略?

棘手的问题,我知道。还有很多东西需要阅读和理解。但如果这很容易,我就不会花力气把它全部放在这里。迫切需要您的帮助。

最佳答案

这些 $id s 和 $ref PreserveReferencesHandling mode 时,Json.NET 在内部使用 s已启用。您不需要关心它们,只需定义您的 RootObject , StyleRoot等类通常没有那个Entity基类和集合 PreserveReferencesHandling模式 JsonSerializerSettings . Json.NET 将处理 $id s 和 $ref在引擎盖下创建一个保留原始引用结构的对象网络:

var obj = JsonConvert.DeserializeObject<RootObject>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });

序列化也可以在保留引用处理模式下完成:

var json = JsonConvert.SerializeObject(obj,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });

演示:https://dotnetfiddle.net/TygMDZ

注意在您的输入数据样本中 "$ref"属性包含一个数值,而 Json.NET 写入并期望 "$ref"属性具有字符串值。可能是因为您不小心发布了一些实验过程中更改的 JSON 文本?

关于c# - 有选择地将实例的属性序列化为 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44261306/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com