2017-05-30 21 views
2

我有一些包含有点奇怪格式的JSON文件。我必须阅读,修改和保存我的项目的这种格式。不幸的是,我对给定的格式没有任何影响。有选择地将实例的属性序列化为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" 
       } 
      } 
     } 
    } 
} 

为了解决这个问题,我创建了一个C#基类实体所有JSON数据类。这个基类维护一个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类hiearchy看起来是这样的:

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$裁判没有有效的JSON字段名标识符。目前,我正在使用正则表达式将其替换为有效的内容,然后将它们重新替换为之前的内容。但是,这是缓慢的。我想知道是否可以使用NamingStrategy来达到同样的效果。但我没有成功。记住,我需要两种方式,反序列化和序列化。
  2. 序列化是一个更难的问题。如果我按照原样序列化结构,那么在每个实例中,我最终都会得到"$id":"$ref":字段。更重要的是,与所引用的项目一起,所有其他字段都使用默认值进行序列化。最简单的方法是在JsonSerializerSettings中简单地设置DefaultValueHandling.IgnoreAndPopulate。但是这样,所有的默认值都会从输出中剥离,导致意外的行为。我试图用ContractResolver去,但因为这是当前属性本地,并且不能考虑周围的实体,所以失败了。有没有其他方法来实现自定义序列化策略?

这个问题很难说,我知道。还有很多东西需要阅读和理解。但如果这很容易,我不会花费精力把它放在这里。迫切需要你的帮助。

回答

1

这些$id S和$ref s的使用Json.NET内部时被启用PreserveReferencesHandling mode。您无需关心它们,只需定义您的RootObject,StyleRoot等类别即可,无需Entity基类,并在JsonSerializerSettings中设置PreserveReferencesHandling模式。 JSON。NET将处理引擎盖下$id S和$ref S和创建对象的网络保留原始参考结构:

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

NB在您的输入数据示例中,"$ref"属性包含一个数字值,而Json.NET写入和期望"$ref"属性具有字符串值。可能是因为你在一些实验过程中意外地发布了改变的JSON文本呢?

+0

完美!适用于我。 你对“$ ref”的价值是正确的。我已经剥去了很多文字,使它更加紧凑。我不得不做一些手动编辑... 顺便说一句,PreserveReferenceHandling.Object和PreserveReferenceHandling.All有什么区别? – freefall

相关问题