更新类中Json属性的名称



我正在尝试更新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,而OldName在json文件中找不到
  • 在任何情况下都不能将值反序列化两次并放入同一个列表

您将如何实现这一点?

试试这个

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;}
}

使用System.Text.Json。

var foo = new myClass()
{
OldName = { "test" },
};
var bar = JsonSerializer.Serialize<myClass>(foo);
var result = JsonSerializer.Deserialize<myClass>(bar);

这个回答很有帮助。基本上你可以这样重构你的代码:

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仍然可用,但标记为obselete
  • 代码将在json文件中读取或者OldName或NewName,但只写入NewName的文件

这是不应该发生的,但如果你仍然以某种方式结束json文件与一个OldName和一个NewName,在OldName和NewName上面添加属性[JsonProperty(ObjectCreationHandling = ObjectCreationHandling.Replace)]-这样它们会相互覆盖,而不是追加。

最新更新