我将以我试图避免使用 Newtonsoft.Json
的事实作为开头。因为,表面上,System.Text.Json
准备好迎接 .NET 6 的黄金时段。
所以我有两个来自 API 的枚举,我想使用这个测试方法反序列化它们:
[Theory]
[ClassData(typeof(TestDataGenerator))]
public void CanDeserialiseEnumsWithCustomJsonStrings(Enum expected, string jsonName)
{
jsonName.ShouldNotBeNullOrEmpty();
ReadOnlySpan<char> json = $"{{\"TestEnum\":\"{jsonName}\"}}";
Type constructed = typeof(TestEnumWrapper<>).MakeGenericType(expected.GetType());
var res = JsonSerializer.Deserialize(json, constructed);
constructed.GetProperty("TestEnum").GetValue(res).ShouldBe(expected);
}
private class TestEnumWrapper<T> where T: struct
{
public T TestEnum { get; set; }
}
(是的,我知道这可以用 JsonSerializer.Deserialize<T>()
来完成,我希望能够用这个测试来测试许多类型,所以我需要反射 AFAICT)。
第一个,工作正常:
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum RecordType
{
[JsonPropertyName("country")]
Country = 1,
[JsonPropertyName("destinationOrbit")]
DestinationOrbit = 2,
[JsonPropertyName("engine")]
Engine = 3,
//etc...
}
第二个,反序列化失败,这似乎是由于名称中的空格。
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ObjectClass
{
[JsonPropertyName("Rocket Body")]
RocketBody,
[JsonPropertyName("Rocket Debris")]
RocketDebris,
[JsonPropertyName("Rocket Fragmentation Debris")]
RocketFragmentationDebris,
[JsonPropertyName("Rocket Mission Related Object")]
RocketMissionRelatedObject,
//etc...
}
API 由欧洲航天局控制,所以不知何故,我认为我无法说服他们对响应进行更多合理化。
有什么办法解决这个问题吗?
有些人要求提供我尝试反序列化的 JSON 示例。我目前正在研究这个 blob 的属性部分:
{
"type": "object",
"attributes": {
"shape": null,
"xSectMin": null,
"satno": null,
"depth": null,
"objectClass": "Rocket Fragmentation Debris",
"cosparId": null,
"length": null,
"height": null,
"mass": null,
"xSectMax": null,
"vimpelId": 84303,
"xSectAvg": null,
"name": null
},
"relationships": {
"states": {
"links": {
"self": "/api/objects/61345/relationships/states",
"related": "/api/objects/61345/states"
}
},
"initialOrbits": {
"links": {
"self": "/api/objects/61345/relationships/initial-orbits",
"related": "/api/objects/61345/initial-orbits"
}
},
"destinationOrbits": {
"links": {
"self": "/api/objects/61345/relationships/destination-orbits",
"related": "/api/objects/61345/destination-orbits"
}
},
"operators": {
"links": {
"self": "/api/objects/61345/relationships/operators",
"related": "/api/objects/61345/operators"
}
},
"launch": {
"links": {
"self": "/api/objects/61345/relationships/launch",
"related": "/api/objects/61345/launch"
}
},
"reentry": {
"links": {
"self": "/api/objects/61345/relationships/reentry",
"related": "/api/objects/61345/reentry"
}
}
},
"id": "61345",
"links": {
"self": "/api/objects/61345"
}
}
最佳答案
这是System.Text.Json
的解决方案
我使用了 Nuget 包 System.Text.Json.EnumExtensions
https://github.com/StefH/System.Text.Json.EnumExtensions
// you probably want these options somewhere global
private JsonSerializerOptions options;
private class TestEnumWrapper<T> where T : struct
{
public T TestEnum { get; set; }
}
public enum ObjectClass
{
[EnumMember(Value = "Rocket Body")]
RocketBody,
[EnumMember(Value = "Rocket Debris")]
RocketDebris,
[EnumMember(Value = "Rocket Fragmentation Debris")]
RocketFragmentationDebris,
[EnumMember(Value = "Rocket Mission Related Object")]
RocketMissionRelatedObject,
//etc...
}
private void CanDeserialiseEnumsWithCustomJsonStrings(Enum expected, string jsonName)
{
var json = $"{{\"TestEnum\":\"{jsonName}\"}}";
Type constructed = typeof(TestEnumWrapper<>).MakeGenericType(expected.GetType());
var res = JsonSerializer.Deserialize(json, constructed, options);
}
public void Test()
{
this.options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverterWithAttributeSupport());
var testSerialize = JsonSerializer.Serialize(new TestEnumWrapper<ObjectClass>()
{ TestEnum = ObjectClass.RocketBody }, options);
// Test Deserialize
CanDeserialiseEnumsWithCustomJsonStrings(ObjectClass.RocketBody, "Rocket Body");
}
您只需将 new JsonStringEnumConverterWithAttributeSupport()
添加到 JsonSerializerOptions.Converters
即可使其工作。
如果要将转换器用作属性,则必须向类 JsonStringEnumConverterWithAttributeSupport 添加无参数构造函数
public JsonStringEnumConverterWithAttributeSupport() : this(namingPolicy : null, allowIntegerValues : true,
parseEnumMemberAttribute : true, parseDisplayAttribute : false, parseDescriptionAttribute : false)
{
}
关于c# - 使用空格从 JSON 字符串反序列化枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70501574/