c# - 使用空格从 JSON 字符串反序列化枚举

标签 c# json enums deserialization system.text.json

我将以我试图避免使用 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/

相关文章:

c# - 在 C# 中以编程方式将文本添加到剪贴板

c# - 我怎样才能让我的碰撞更稳固?

json - Safaricom 达拉贾 : Duplicate json key detected

C 预处理器和枚举 – 我的代码中有错误吗?

Scala json4s 密封特征作为枚举

c# - 使用 WMI 或 System.Diagnostics 类的几个非常奇怪的性能计数器

c# - 如何以编程方式从我的 Windows 10 应用程序启动相机应用程序?

java - Java 上带有 MultiValueMap 的 JSON

php - JSON_Encode 输出奇数额外值

c++ - 枚举成员的值,当某些成员具有用户定义的值时