我有一些包含某种奇怪格式的 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# 基类实体。这个基类维护一个 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; }
}
到现在为止还挺好。现在我的问题:
[JsonProperty("$id")]
并且[JsonProperty("$ref")]
不起作用,因为$id和$ref不是有效的 JSON 字段名称标识符。目前,我正在使用正则表达式将它们替换为有效的内容,然后将它们重新替换回原来的状态。但这是迟钝的。我想知道我是否可以使用NamingStrategy
来实现相同的目标。但我没有成功。请记住,我需要两种方式,反序列化和序列化。"$id":
和"$ref":
字段。更重要的是,连同引用的项目,所有其他字段都使用默认值进行序列化。最简单的方法是简单地DefaultValueHandling.IgnoreAndPopulate
在JsonSerializerSettings
. 但是这样,所有默认值都会从输出中删除,这会导致意外行为。我尝试使用 aContractResolver
但失败了,因为这是当前属性的本地属性,无法将周围的实体考虑在内。还有其他方法可以实现自定义序列化策略吗?棘手的问题,我知道。还有很多东西要阅读和理解。但如果这很容易,我就不会费力把它全部放在这里。迫切需要您的帮助。
当模式启用时,这些$id
s 和$ref
s 由 Json.NET 在内部使用。你并不需要关心他们,只是定义,等类,通常没有这种基础类和集的模式。Json.NET 将处理引擎盖下的s 和s 并创建一个保留原始引用结构的对象网络:PreserveReferencesHandling
RootObject
StyleRoot
Entity
PreserveReferencesHandling
JsonSerializerSettings
$id
$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 文本?
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句