[英]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.