从带有空格的 JSON 字符串反序列化枚举

Per*_*nce 3 c# enums json 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; }
}
Run Code Online (Sandbox Code Playgroud)

(是的,我知道这可以通过 来完成JsonSerializer.Deserialize<T>(),我希望能够通过此测试测试许多类型,所以我需要反射 AFAICT)。

第一个,工作正常:

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum RecordType
{
        [JsonPropertyName("country")]
        Country = 1,

        [JsonPropertyName("destinationOrbit")]
        DestinationOrbit = 2,

        [JsonPropertyName("engine")]
        Engine = 3,
        //etc...

}
Run Code Online (Sandbox Code Playgroud)

第二个,反序列化失败,这似乎是由于名称中的空格造成的。

[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...
}
Run Code Online (Sandbox Code Playgroud)

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"
            }
        }
Run Code Online (Sandbox Code Playgroud)

Cha*_*les 6

这是一个解决方案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");
}
Run Code Online (Sandbox Code Playgroud)

您只需将 添加到new JsonStringEnumConverterWithAttributeSupport()即可JsonSerializerOptions.Converters使其工作。

如果您想使用转换器作为属性,您必须向类添加无参数构造函数JsonStringEnumConverterWithAttributeSupport

public JsonStringEnumConverterWithAttributeSupport() : this(namingPolicy : null, allowIntegerValues : true,
    parseEnumMemberAttribute : true, parseDisplayAttribute : false, parseDescriptionAttribute : false)
{

}
Run Code Online (Sandbox Code Playgroud)