当C#端没有等效值时,我们如何处理Enum的反序列化错误?

How we can handle deserializing error of Enum when there is no equivalent value in C# side?

在我的 C# 代码中,我有一个枚举类型将作为字符串存储在 MongoDB 中。在我的 C# 代码中,我有这种类型:

public enum Color
{
    Unknown =0,
    Red =1,
    Blue =2,
    Brown =3,
}

当 MongoDB 中的字符串值为红色、蓝色或棕色时没有问题,但有时在 DB 中还有其他颜色未包含在我的枚举类型中,例如黑色,在这种情况下,我希望颜色反序列化为未知,但反序列化错误表明未定义黑色。有什么办法可以解决这个问题吗?我无法在我这边添加所有颜色,也无法将枚举类型更改为任何其他类型。我想知道如何将它反序列化为 Unknown?

您可以使用自定义 StringEnumConverter。这将 return 您的默认枚举值

public class SafeStringEnumConverter : StringEnumConverter
{
    public object DefaultValue { get; }

    public SafeStringEnumConverter(object defaultValue)
    {
        DefaultValue = defaultValue;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }
        catch
        {      
            return DefaultValue;
        }
    }
}

您可以像这样在您的枚举中使用它

那你就可以这样使用了:

[JsonConverter(typeof(SafeStringEnumConverter), Unknown)]

    public enum Colors
    {
        Unknown=0,
        Red =1,
        Blue =2,
        Brown =3
    }

您将需要像这样的自定义序列化程序:

public class ColorSerializer : SerializerBase<Color>
{
    public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, Color value)
    {
        ctx.Writer.WriteString(value.ToString());
    }

    public override Color Deserialize(BsonDeserializationContext ctx, BsonDeserializationArgs args)
    {
        return
            ctx.Reader.CurrentBsonType switch
            {
                MongoDB.Bson.BsonType.String => ctx.Reader.ReadString() switch
                {
                    "Red" => Color.Red,
                    "Blue" => Color.Blue,
                    "Brown" => Color.Brown,
                    _ => Color.Unknown,
                },
                _ => Color.Unknown,
            };
    }
}

在应用程序启动期间将其注册到序列化程序注册表,如下所示:

BsonSerializer.RegisterSerializer(typeof(Color), new ColorSerializer());

完成!

另一个选项是 MongoDB 驱动程序 (BSON) 的自定义通用枚举序列化程序,这将允许您在注册序列化程序时定义默认值

public class EnumSerializer<T> : SerializerBase<T> where T : struct
{
    public T DefaultValue { get; }

    public EnumSerializer(T defaultValue)
    {
        DefaultValue = defaultValue;
    }

    public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, T value)
    {
        ctx.Writer.WriteString(value.ToString());
    }

    public override T Deserialize(BsonDeserializationContext ctx, BsonDeserializationArgs args)
    {
        if (ctx.Reader.CurrentBsonType == MongoDB.Bson.BsonType.Null)
        {
            ctx.Reader.ReadNull();
            return DefaultValue;
        }
        if (ctx.Reader.CurrentBsonType == MongoDB.Bson.BsonType.String)
        {
            var value = ctx.Reader.ReadString();
            if (Enum.TryParse<T>(value, true, out var res))
                return res;
        }
        return DefaultValue;
    }
}

你可以这样使用它

BsonSerializer.RegisterSerializer(typeof(CurrancyCode), new EnumSerializer<CurrancyCode>(CurrancyCode.GBP));