C# System.Text.Json 列舉(enum)使用成員名稱序列化和反序列化

在 C# 中建立了一個列舉(enum)如下:
    
public enum UserStatus
{
    Normal,
    Disabled,
    Deleted,
}
    

建立一個簡單的 class:
    
public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public UserStatus Status { get; set; }
}
    

將物件序列化為 Json:
    
UserDto dto = new()
{
    Id = 1,
    Name = "Ruyut",
    Status = UserStatus.Normal,
};

string serialized = JsonSerializer.Serialize(dto);
Console.WriteLine($"user: {serialized}");
// user: {"Id":1,"Name":"Ruyut","Status":0}
    

咦?Status 居然是 0 而不是 Normal?那將 JSON 反序列化為物件呢?
    
string json = @"{
    ""Id"": 1,
    ""Name"": ""Ruyut"",
    ""Status"": ""Normal""
}";

UserDto? user = JsonSerializer.Deserialize<UserDto>(json);
    

直接拋出例外:
    
System.Text.Json.JsonException: The JSON value could not be converted to UserStatus. Path: $.Status | LineNumber: 9 | BytePositionInLine: 22.
   at System.Text.Json.ThrowHelper.ThrowJsonException(String message)
   at System.Text.Json.Serialization.Converters.EnumConverter`1.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 utf8Json, JsonTypeInfo jsonTypeInfo, Nullable`1 actualByteCount)
   at System.Text.Json.JsonSerializer.ReadFromSpan[TValue](ReadOnlySpan`1 json, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Program.<Main>$(String[] args) in C:\Users\ruyut\Documents\RiderProjects\2023\test\ConsoleAppJsonElementTest\ConsoleAppJsonElementTest\Program.cs:line 7
    

也要使用數字的方式才可以成功把 JSON 反序列化為物件:
    
string json = @"{
    ""Id"": 1,
    ""Name"": ""Ruyut"",
    ""Status"": 0
}";

UserDto? user = JsonSerializer.Deserialize<UserDto>(json);
    

但是如果就是想要使用列舉的成員名稱該怎麼做?非常簡單,只要在 enum 上面加上一行程式碼,標記要使用內建的列舉轉換器即可:
    
using System.Text.Json.Serialization;

[JsonConverter(typeof(JsonStringEnumConverter))]
public enum UserStatus
{
    Normal,
    Disabled,
    Deleted,
}
    

這樣就可以使用 enum 的 name 了:
    
string json = @"{
    ""Id"": 1,
    ""Name"": ""Ruyut"",
    ""Status"": ""Normal""
}";


UserDto? user = JsonSerializer.Deserialize<UserDto>(json);
string serialized = JsonSerializer.Serialize(user);
Console.WriteLine($"user: {serialized}");
// user: {"Id":1,"Name":"Ruyut","Status":"Normal"}
    

並且就算是和之前一樣使用 0, 1, 2 也可以正確被解析:
    
string json = @"{
    ""Id"": 1,
    ""Name"": ""Ruyut"",
    ""Status"": 2
}";

UserDto? user = JsonSerializer.Deserialize<UserDto>(json);
string serialized = JsonSerializer.Serialize(user);
Console.WriteLine($"user: {serialized}");
// user: {"Id":1, "Name":"Ruyut","Status":"Deleted"}
    

留言