C# MongoDB中枚举的自定义序列化
在Json.NET中引用这一点是关于字符串到枚举的自定义序列化,反之亦然,使用EnumMember属性修饰枚举成员-有没有办法让MongoDB执行相同的功能C# MongoDB中枚举的自定义序列化,c#,mongodb,serialization,enums,C#,Mongodb,Serialization,Enums,在Json.NET中引用这一点是关于字符串到枚举的自定义序列化,反之亦然,使用EnumMember属性修饰枚举成员-有没有办法让MongoDB执行相同的功能 我刚刚将一些以前的字符串字段重构为Enum,并想知道是否有任何方法可以指示Mongo在(反)序列化时也读取EnumMember值,从而避免我必须遍历数据库并更新所有当前文本值。我使用CustomEnumSerializer来处理EnumMember属性 public class CustomEnumSerializer<TEnum&g
我刚刚将一些以前的字符串字段重构为Enum,并想知道是否有任何方法可以指示Mongo在(反)序列化时也读取EnumMember值,从而避免我必须遍历数据库并更新所有当前文本值。我使用CustomEnumSerializer来处理EnumMember属性
public class CustomEnumSerializer<TEnum> : StructSerializerBase<TEnum>, IRepresentationConfigurable<CustomEnumSerializer<TEnum>> where TEnum : struct
{
private static readonly Dictionary<Type, Dictionary<string, object>> _fromValueMap = new Dictionary<Type, Dictionary<string, object>>(); // string representation to Enum value map
private static readonly Dictionary<Type, Dictionary<object, string>> _toValueMap = new Dictionary<Type, Dictionary<object, string>>(); // Enum value to string map
// private fields
private readonly BsonType _representation;
// constructors
/// <summary>
/// Initializes a new instance of the <see cref="EnumSerializer{TEnum}"/> class.
/// </summary>
public CustomEnumSerializer()
: this((BsonType)0) // 0 means use underlying type
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EnumSerializer{TEnum}"/> class.
/// </summary>
/// <param name="representation">The representation.</param>
public CustomEnumSerializer(BsonType representation)
{
switch (representation)
{
case 0:
case BsonType.Int32:
case BsonType.Int64:
case BsonType.String:
break;
default:
var message = string.Format("{0} is not a valid representation for an EnumSerializer.", representation);
throw new ArgumentException(message);
}
// don't know of a way to enforce this at compile time
var enumTypeInfo = typeof(TEnum).GetTypeInfo();
if (!enumTypeInfo.IsEnum)
{
var message = string.Format("{0} is not an enum type.", typeof(TEnum).FullName);
throw new BsonSerializationException(message);
}
_representation = representation;
if (representation == BsonType.String)
{
var enumType = typeof(TEnum);
if (!_fromValueMap.ContainsKey(enumType))
{
Dictionary<string, object> fromMap = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
Dictionary<object, string> toMap = new Dictionary<object, string>();
FieldInfo[] fields = enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (FieldInfo field in fields)
{
string name = field.Name;
object enumValue = Enum.Parse(enumType, name);
// use EnumMember attribute if exists
EnumMemberAttribute enumMemberAttrbiute = field.GetCustomAttribute<EnumMemberAttribute>();
if (enumMemberAttrbiute != null)
{
string enumMemberValue = enumMemberAttrbiute.Value;
fromMap[enumMemberValue] = enumValue;
toMap[enumValue] = enumMemberValue;
}
else
{
toMap[enumValue] = name;
}
fromMap[name] = enumValue;
}
_fromValueMap[enumType] = fromMap;
_toValueMap[enumType] = toMap;
}
}
}
// public properties
/// <summary>
/// Gets the representation.
/// </summary>
/// <value>
/// The representation.
/// </value>
public BsonType Representation
{
get { return _representation; }
}
// public methods
/// <summary>
/// Deserializes a value.
/// </summary>
/// <param name="context">The deserialization context.</param>
/// <param name="args">The deserialization args.</param>
/// <returns>A deserialized value.</returns>
public override TEnum Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var bsonType = bsonReader.GetCurrentBsonType();
switch (bsonType)
{
case BsonType.Int32: return (TEnum)Enum.ToObject(typeof(TEnum), bsonReader.ReadInt32());
case BsonType.Int64: return (TEnum)Enum.ToObject(typeof(TEnum), bsonReader.ReadInt64());
case BsonType.Double: return (TEnum)Enum.ToObject(typeof(TEnum), (long)bsonReader.ReadDouble());
case BsonType.String:
var fromValue = FromValue(typeof(TEnum), bsonReader.ReadString());
return (TEnum)Enum.Parse(typeof(TEnum), fromValue.ToString());
default:
throw CreateCannotDeserializeFromBsonTypeException(bsonType);
}
}
/// <summary>
/// Serializes a value.
/// </summary>
/// <param name="context">The serialization context.</param>
/// <param name="args">The serialization args.</param>
/// <param name="value">The object.</param>
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TEnum value)
{
var bsonWriter = context.Writer;
switch (_representation)
{
case 0:
var underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(typeof(TEnum)));
if (underlyingTypeCode == TypeCode.Int64 || underlyingTypeCode == TypeCode.UInt64)
{
goto case BsonType.Int64;
}
else
{
goto case BsonType.Int32;
}
case BsonType.Int32:
bsonWriter.WriteInt32(Convert.ToInt32(value));
break;
case BsonType.Int64:
bsonWriter.WriteInt64(Convert.ToInt64(value));
break;
case BsonType.String:
var val = ToValue(typeof(TEnum), value);
bsonWriter.WriteString(val);
break;
default:
throw new BsonInternalException("Unexpected EnumRepresentation.");
}
}
private string ToValue(Type enumType, object obj)
{
Dictionary<object, string> map = _toValueMap[enumType];
return map[obj];
}
private object FromValue(Type enumType, string value)
{
Dictionary<string, object> map = _fromValueMap[enumType];
if (!map.ContainsKey(value))
return value;
return map[value];
}
/// <summary>
/// Returns a serializer that has been reconfigured with the specified representation.
/// </summary>
/// <param name="representation">The representation.</param>
/// <returns>The reconfigured serializer.</returns>
public CustomEnumSerializer<TEnum> WithRepresentation(BsonType representation)
{
if (representation == _representation)
{
return this;
}
else
{
return new CustomEnumSerializer<TEnum>(representation);
}
}
// explicit interface implementations
IBsonSerializer IRepresentationConfigurable.WithRepresentation(BsonType representation)
{
return WithRepresentation(representation);
}
}
公共类CustomEnumSerializer:StructSerializerBase,IRepresentationConfigurable其中TEnum:struct
{
私有静态只读字典_fromValueMap=new Dictionary();//枚举值映射的字符串表示
私有静态只读字典_toValueMap=new Dictionary();//枚举值到字符串映射
//私人领域
私有只读BsonType_表示;
//建设者
///
///初始化类的新实例。
///
公共CustomEnumSerializer()
:此((BsonType)0)//0表示使用基础类型
{
}
///
///初始化类的新实例。
///
///代表。
公共CustomEnumSerializer(BsonType表示)
{
开关(表示)
{
案例0:
案例BsonType.Int32:
案例BsonType.Int64:
case BsonType.String:
打破
违约:
var message=string.Format(“{0}不是枚举序列化程序的有效表示形式。”,表示形式);
抛出新的ArgumentException(消息);
}
//不知道如何在编译时强制执行此操作
var enumTypeInfo=typeof(TEnum).GetTypeInfo();
如果(!enumTypeInfo.IsEnum)
{
var message=string.Format(“{0}不是枚举类型。”,typeof(TEnum.FullName);
抛出新的BsonSerializationException(消息);
}
_代表性=代表性;
if(表示==BsonType.String)
{
var enumType=typeof(TEnum);
if(!\u fromValueMap.ContainsKey(枚举类型))
{
Dictionary fromMap=新字典(StringComparer.InvariantCultureInogoreCase);
Dictionary toMap=新字典();
FieldInfo[]fields=enumType.GetFields(BindingFlags.Static | BindingFlags.Public);
foreach(字段中的字段信息字段)
{
字符串名称=field.name;
object enumValue=Enum.Parse(enumType,name);
//如果存在,请使用EnumMember属性
EnumMemberAttribute EnumMemberAttribute=字段。GetCustomAttribute();
if(EnumMemberAttribute!=null)
{
字符串enumMemberValue=EnumMemberAttribute.Value;
fromMap[enumMemberValue]=enumValue;
toMap[enumValue]=enumMemberValue;
}
其他的
{
toMap[enumValue]=名称;
}
fromMap[name]=枚举值;
}
_fromValueMap[enumType]=fromMap;
_toValueMap[enumType]=toMap;
}
}
}
//公共财产
///
///获取表示形式。
///
///
///代表。
///
公共BsonType表示
{
获取{返回_表示;}
}
//公共方法
///
///反序列化一个值。
///
///反序列化上下文。
///反序列化args。
///反序列化的值。
公共重写TEnum反序列化(BsonDeserializationContext,BsonDeserializationArgs-args-args)
{
var bsonReader=context.Reader;
var bsonType=bsonReader.GetCurrentBsonType();
开关(bsonType)
{
案例BsonType.Int32:return(TEnum)Enum.ToObject(typeof(TEnum),bsonReader.ReadInt32());
案例BsonType.Int64:return(TEnum)Enum.ToObject(typeof(TEnum),bsonReader.ReadInt64());
case BsonType.Double:return(TEnum)Enum.ToObject(typeof(TEnum),(long)bsonReader.ReadDouble();
case BsonType.String:
var fromValue=fromValue(typeof(TEnum),bsonReader.ReadString());
return(TEnum)Enum.Parse(typeof(TEnum),fromValue.ToString());
违约:
抛出CreateConnotDeserializeFromBSontypeException(bsonType);
}
}
///
///序列化一个值。
///
///序列化上下文。
///序列化参数为。
///物体。
public override void Serialize(BsonSerializationContext,BsonSerializationArgs参数,TEnum值)
{
var bsonWriter=context.Writer;
开关(_表示)
{
案例0:
var underfullyingtypecode=Type.GetTypeCode(Enum.getunderyingtype(typeof(TEnum));
if(underlyngtypecode==TypeCode.Int64 | | underlyngtypecode==TypeCode.UInt64)
{
转到案例BsonType.Int64;
}
其他的
{
转到案例BsonType.Int32;
}
案例BsonType.Int32:
bsonWriter.WriteInt32(转换为32(值));
打破
案例BsonType.Int64:
bsonWriter.WriteInt64(转换为64(值));
打破
case BsonType.String:
var val=ToValue(类型(TEnum),值);
bsonWriter.WriteString(val);
打破
违约:
抛出新的BsonInternalException(“意外的枚举表示”);
}
}
私有字符串ToValue(类型enumType,
public class CustomEnumSerializer<TEnum>: MongoDB.Bson.Serialization.Serializers.EnumSerializer<TEnum>
where TEnum : struct, IComparable, IFormattable, IConvertible
{
public override TEnum Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var bsonType = bsonReader.GetCurrentBsonType();
var val = "";
switch (bsonType)
{
case BsonType.String:
val = bsonReader.ReadString() ?? "";
break;
case BsonType.Int32:
val = bsonReader.ReadInt32().ToString();
break;
case BsonType.Int64:
val = bsonReader.ReadInt64().ToString();
break;
case BsonType.Null:
return default(TEnum);
default:
return base.Deserialize(context, args);
}
if(Enum.TryParse(val, true, out TEnum result)){
return result;
}
return default(TEnum);
}
}
static MyRepository()
{
BsonClassMap.RegisterClassMap<MyDataType>(ms =>
{
ms.AutoMap();
ms.GetMemberMap(i => i.MyEnum)
.SetSerializer(new CustomEnumSerializer<MyEnumType>());
});
}
public class OfferMap
{
public static void Configure()
{
BsonClassMap.RegisterClassMap<Offer>(map => //Offer is a class
{
map.AutoMap();
map.SetIgnoreExtraElements(true);
map
.SetIsRootClass(true);
map
.MapMember(x => x.OfferType)
.SetSerializer(new EnumSerializer<OfferType>(MongoDB.Bson.BsonType.String)) // OfferType is an Enum
.SetElementName("offerType")
.SetIgnoreIfNull(false)
.SetIsRequired(true);