簡體   English   中英

MongoDb C# 驅動程序 - 序列化列表<enum>作為字符串[]

[英]MongoDb C# driver - serializing List<enum> as string[]

我有一個屬性類型為List<SomeEnum> 像這樣的東西:

public enum MyEnum
{
  A,
  B
}

public class MyClass
{
    public string Id { get; set; }
    public List<MyEnum> Values { get; set; }
}

我已經在以這種方式使用EnumRepresentationConvention

ConventionRegistry.Register("EnumStringConvention", new ConventionPack { new EnumRepresentationConvention(BsonType.String) }, t => true);

盡管如此, Values屬性仍被序列化為一個整數數組(簡單的枚舉屬性被正確地處理為整數)。 似乎在列表序列化的上下文中不使用該約定。

如何強制序列化程序寫入字符串而不是整數?

不是調用ConventionRegistry.Register() ,而是將數據注釋[BsonRepresentation(BsonType.String)]到 MyClass 的屬性Values

public class MyClass
{
    public string Id { get; set; }

    [BsonRepresentation(BsonType.String)] 
    public List<MyEnum> Values { get; set; }
}

之后更改collection.InsertOne(obj); 正在保存這個:

{
    "_id" : "1",
    "Values" : [ 
        "A", 
        "B"
    ]
}

唉,這個 PR 已被關閉,無法修復。 https://github.com/mongodb/mongo-csharp-driver/pull/305#issuecomment-731475503

對此給出了很好的理由,但我認為這是人們想要做的事情,因此根據您對跳過箍的興趣,您可以嘗試這個(.NET 5):

using System;
using System.Collections.Generic;
using System.Reflection;

using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;

public sealed class EnumWrapper<TEnum>
    where TEnum : struct, Enum
{
    [BsonConstructor]
    public EnumWrapper(TEnum value) => this.Value = value;

    public TEnum Value { get; }

    public static readonly IBsonSerializer<EnumWrapper<TEnum>> Serializer = new BsonSerializerImpl();

    public static implicit operator TEnum(EnumWrapper<TEnum> wrapper) => wrapper.Value;

    public static implicit operator EnumWrapper<TEnum>(TEnum value) => new(value);

    public override bool Equals(object obj) =>
        obj is EnumWrapper<TEnum> wrapper
        && EqualityComparer<TEnum>.Default.Equals(this.Value, wrapper.Value);

    public override int GetHashCode() => HashCode.Combine(this.Value);

    public override string ToString() => this.Value.ToString();

    private class BsonSerializerImpl : IBsonSerializer<EnumWrapper<TEnum>>
    {
        public Type ValueType => typeof(EnumWrapper<TEnum>);

        public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, EnumWrapper<TEnum> value) =>
            context.Writer.WriteString(((TEnum)value).ToString());

        public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) =>
            this.Serialize(context, args, (EnumWrapper<TEnum>)value);

        object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) =>
            this.Deserialize(context, args);

        public EnumWrapper<TEnum> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) =>
            Enum.Parse<TEnum>(context.Reader.ReadString());
    }
}

public class EnumWrapperBsonSerializationProvider : IBsonSerializationProvider
{
    public IBsonSerializer GetSerializer(Type type)
    {
        if (!type.IsGenericType)
        {
            return null;
        }

        var typeDefinition = type.GetGenericTypeDefinition();
        if (typeDefinition != typeof(EnumWrapper<>))
        {
            return null;
        }

        var field = type.GetField(nameof(EnumWrapper<Hack>.Serializer), BindingFlags.Public | BindingFlags.Static);
        return (IBsonSerializer)field.GetValue(null);
    }

    private enum Hack { }
}

現在您可以在通常使用TEnum任何地方使用EnumWrapper<TEnum>並且它會做您想做的事情。 如果您不注冊序列化提供程序,它將序列化為嵌套對象,因此在執行任何操作之前,您應該調用它:

BsonSerializer.RegisterSerializationProvider(new EnumWrapperBsonSerializationProvider());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM