我有一个类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
属性被序列化为一个int数组(简单的枚举属性被正确处理为int)。似乎在列表序列化的上下文中没有使用约定。
如何强制序列化程序编写字符串而不是整数?
答案 0 :(得分:3)
不是调用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"
]
}
答案 1 :(得分:2)
可惜此 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 { }
}
现在您可以在通常使用 EnumWrapper<TEnum>
的地方使用 TEnum
,它会做您想做的事。如果您不注册序列化提供程序,它将序列化为嵌套对象,因此在执行任何操作之前您应该调用它:
BsonSerializer.RegisterSerializationProvider(new EnumWrapperBsonSerializationProvider());