C# 选择性地将实例的属性序列化为JSON
我有一些JSON文件,其中包含一种有点奇怪的格式。我必须为我的项目阅读、修改和保存此格式。不幸的是,我对给定的格式没有任何影响 这种格式的奇怪之处在于,该结构中的所有实体都有一个唯一的标识符(无效地)称为“$id”。这些实例也可以通过它们的id而不是它们的完整属性集来引用。在本例中,没有“$id”,而是有一个“$ref”字段,其中包含一个已定义的实体。请看下面的(缩短的)示例:C# 选择性地将实例的属性序列化为JSON,c#,json.net,C#,Json.net,我有一些JSON文件,其中包含一种有点奇怪的格式。我必须为我的项目阅读、修改和保存此格式。不幸的是,我对给定的格式没有任何影响 这种格式的奇怪之处在于,该结构中的所有实体都有一个唯一的标识符(无效地)称为“$id”。这些实例也可以通过它们的id而不是它们的完整属性集来引用。在本例中,没有“$id”,而是有一个“$ref”字段,其中包含一个已定义的实体。请看下面的(缩短的)示例: { "$id": "1", "StyleName": "Standard", "Style":
{
"$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;
}
}
}
到目前为止,一切顺利。现在回答我的问题:
[JsonProperty(“$id”)]
和[JsonProperty($ref”)]
不起作用,因为$id和$ref不是有效的JSON字段名标识符。目前,我正在使用正则表达式将它们替换为有效的内容,然后将它们重新替换回原来的状态。但这是缓慢的。我想知道我是否可以使用NamingStrategy
来实现同样的目标。但我没有成功。记住,我需要两种方式,反序列化和序列化“$id”:
和“$ref”:
字段。此外,所有其他字段与被引用项一起使用默认值序列化。最简单的方法是在JsonSerializerSettings
中简单地设置DefaultValueHandling.IgnoreAndPopulate
。但这样,所有默认值都会从输出中剥离,从而导致意外行为。我尝试使用ContractResolver
,但失败了,因为这是当前属性的本地属性,无法考虑周围的实体。有没有其他方法来实现自定义序列化策略棘手的问题,我知道。还有很多东西需要阅读和理解。但是如果这很容易的话,我就不会把所有的东西都放在这里了。非常需要您的帮助。这些
$id
s和$ref
s在启用后由Json.NET内部使用。你不需要关心它们,只要定义你的RootObject
,StyleRoot
等类,通常没有实体
基类,并在JsonSerializerSettings
中设置PreserveReferencesHandling
模式。Json.NET将处理引擎盖下的$id
s和$ref
s,并创建一个保留原始引用结构的对象网络:
var obj = JsonConvert.DeserializeObject<RootObject>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
演示:
注意:在您的输入数据样本中,
“$ref”
属性包含一个数值,而Json.NET写入并期望“$ref”
属性具有字符串值。可能是因为您在一些实验过程中无意中发布了更改过的JSON文本吗?太完美了!对我有用。关于“$ref”值,您是对的。为了使它更紧凑,我删去了很多文本。我不得不做一些手工编辑。。。顺便问一下,PreserveReferenceHandling.Object和PreserveReferenceHandling.All之间有什么区别?
var obj = JsonConvert.DeserializeObject<RootObject>(json,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.All });
var json = JsonConvert.SerializeObject(obj,
new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects });