更新类中 Json 属性的名称
Posted
技术标签:
【中文标题】更新类中 Json 属性的名称【英文标题】:Updating the name of a Json Property in a class 【发布时间】:2021-12-07 12:13:14 【问题描述】:我正在尝试更新已发布的 Json 可序列化类中的属性名称,因此我需要使其向后兼容。
public class myClass
//[JsonIgnore] - now old json files can't be read, so this won't work...
//[JsonProperty(ReferenceLoopHandling = ReferenceLoopHandling.Error)] - didn't do anything
//[JsonProperty(nameof(NewName)] - throws error - "That already exists"
[Obselete("Use NewName instead")]
public List<string> OldName get => newName; set => newName = value;
public List<string> NewName get; set; = new List<string>();
我是这样使用它的:
[Test]
public void test()
var foo = new myClass()
OldName = "test" ,
;
var bar = JsonConvert.SerializeObject(foo);
var result = JsonConvert.DeserializeObject(bar, typeof(myClass));
当我查看 result.NewName 中的值时,我发现了这个列表:"test", "test"
,但我期望这个列表:"test"
期望的行为:
如果有人已经在他们的代码中使用 OldName,他们会收到过时警告 如果有人解析包含 OldName 的旧 json 文件,它会正确映射到 NewName 创建的新 json 文件使用 NewName,而在 json 文件中的任何位置都找不到 OldName 在任何情况下都不会将值反序列化两次并放入同一个列表中你会如何做到这一点?
【问题讨论】:
我会为这种类型创建自定义转换器。 将 [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)] 放在 OldName 和 NewName 上会阻止它附加到列表中,但不会阻止 Json 中的重复属性 【参考方案1】:试试这个
var foo = "\"OldName\":[\"old test\"]";
var fooN = "\"NewName\":[\"new test\"]";
var result = JsonConvert.DeserializeObject(foo, typeof(myClass));
//or
var result = JsonConvert.DeserializeObject(fooN, typeof(myClass));
var json = JsonConvert.SerializeObject(result);
json 结果:
"NewName":["new test"]
//or
"NewName":["old test"]
类
public class myClass
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<string> OldName
get return null;
set NewName=value;
public List<string> NewName get; set;
【讨论】:
太棒了!不幸的是,就我而言,我现在仍然需要允许人们访问 OldName 属性。但我相信你的回答会帮助别人!感谢您的关注!【参考方案2】:这适用于 System.Text.Json。
var foo = new myClass()
OldName = "test" ,
;
var bar = JsonSerializer.Serialize<myClass>(foo);
var result = JsonSerializer.Deserialize<myClass>(bar);
【讨论】:
但是 json 字符串包含两个值:"OldName":["test","test2"],"NewName":["test","test2"]。解串器可以对 json 数组使用“附加”模式。这可以解释当 OldName 被反序列化时,OldName 设置了 2 个值(以及 NewName),然后反序列化器读取 NewName 并将 json 中的 2 个值附加到来自 OldName 的 List 的已经 2 个值中。 是的。我想知道是否将 [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)] 放在属性上会阻止它们追加。【参考方案3】:这个answer 很有帮助。基本上你像这样重构你的代码:
public class ControlReportResult : TargetReportResult
public List<string> NewName get; set; = new();
[JsonIgnore] // this stops the serializer from paying attention to this property
[Obsolete("Use NewName instead")]
public List<string> OldName => get => NewName; set => NewName = value;
[JsonProperty("OldName")] //This doesn't throw an error because the serializer was told to ignore the real OldName property
private List<string> _jsonOldNameSetter set => NewName = value; // no getter, so we are never going to write OldName out.
一些注意事项:
_jsonOldNameSetter 是私有的,所以你的界面还是干净的 OldName 仍然可用,但标记为已过时 代码将读取带有要么 OldName 或NewName 的json 文件,但只会写入带有NewName 的文件这不应该发生,但是如果您仍然以某种方式最终得到一个带有 一个 OldName 和一个 NewName 的 json 文件,请在 OldName 和 NewName 上方添加属性 [JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]
- 这样他们会相互覆盖,而不是追加。
【讨论】:
以上是关于更新类中 Json 属性的名称的主要内容,如果未能解决你的问题,请参考以下文章