MongoDB序列化字典<MyEnum,object>



我有一个带有一些Dictionary<MyEnum, object>的模型。当我尝试用C#驱动程序插入mongoDB时,出现了一个异常,显示以下消息:

使用DictionaryRepresentation.Document键值必须序列化为字符串。

当然,我可以添加属性[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)],它可以工作,但我希望能够将枚举持久化为字符串。

public MyEnum {
  A,
  B
}
[BsonDictionaryOptions(DictionaryRepresentation.Document)]
public Dictionary<MyEnum, object> MyData { get; set; }

出于不同的原因,我想在蒙戈有这样的东西。

{
   "MyData": {
      "B": "xxxx",
      "A": "xxxx"
   }
}

对于单个枚举,我只能使用[BsonRepresentation(BsonType.String)]属性,但如何告诉字典的驱动程序将枚举键序列化为字符串?

问题是字典序列化程序没有强制键为字符串类型。为了解决这个问题,创建一个自己的序列化程序,并使用BsonSerializer属性选择它。

public class EnumDictionarySerializer<TKey, TDictionary> : DictionarySerializerBase<TDictionary> 
    where TKey : struct, Enum
    where TDictionary : class, IDictionary, new()
{
    public EnumDictionarySerializer():base(DictionaryRepresentation.Document, new EnumSerializer<TKey>(BsonType.String), new ObjectSerializer())
    {
    }
    protected override TDictionary CreateInstance()
    {
        return new TDictionary();
    }
}

基于@Hugh.walsh的回答,我创建了一个灵活的DictionarySerializer,可以使用键和值的序列化程序进行配置。

public class DictionarySerializer<TDictionary, KeySerializer, ValueSerializer> : DictionarySerializerBase<TDictionary>
    where TDictionary : class, IDictionary, new()
    where KeySerializer : IBsonSerializer, new()
    where ValueSerializer : IBsonSerializer, new()
{
    public DictionarySerializer() : base(DictionaryRepresentation.Document, new KeySerializer(), new ValueSerializer())
    {
    }
    protected override TDictionary CreateInstance()
    {
        return new TDictionary();
    }
}
public class EnumStringSerializer<TEnum> : EnumSerializer<TEnum>
    where TEnum : struct
{
    public EnumStringSerializer() : base(BsonType.String) { }
}

用法如下,其中键和值都是枚举类型,但可以是任何类型:

    [BsonSerializer(typeof(DictionarySerializer<
        Dictionary<MyEnumA, MyEnumB>, 
        EnumStringSerializer<MyEnumA>,
        EnumStringSerializer<MyEnumB>>))]
    public Dictionary<MyEnumA, MyEnumB> FeatureSettings { get; set; }

这个答案对于注释来说太长了,但它引用了一个注释。

这将需要在程序运行时进行反射以更改此对象的类型。一开始这是一个非常糟糕的主意,第二次这会非常缓慢。

我建议您将字典实现用于此目的,或者使用扩展类:

public MyEnum {
  A,
  B
}
[BsonDictionaryOptions(DictionaryRepresentation.Document)]
public MyDictionary<String, MyEnum, object> MyData {get;set;}
public class MyDictionary<T1,T2,T3> : IDictionary{
    Dictionary<T1, T3> Dict = new Dictionary<T1, T3>();
    //implement dictionary...
}
public static class ExtentionsDictionary<T1,T2>{
    public static T2 Get(this IDictionary dict, MyEnum enum){
    var key = enum.ToString();
    return dict[key];
    }
    //Rest of the implementation
}

在Hugh.walsh答案的基础上,我试图获得一个Dictionary<MyEnum, string>字段来序列化。。。

[BsonSerializer(typeof(FiltersSerializer))]
public Dictionary<MyEnum, string> Filters { get; set; } = new ();
...
public class FiltersSerializer: DictionarySerializerBase<Dictionary<MyEnum, string>>
{
    public FiltersSerializer(): base(DictionaryRepresentation.Document, new EnumSerializer<MyEnum>(BsonType.String), new StringSerializer())
    {
    }
 
    protected override Dictionary<MyEnum, string> CreateInstance()
    {
        return new Dictionary<MyEnum, string>();
    }
}

编辑:但我也刚刚学会了在初始化时使用此调用可以获得相同的结果。。。

 MongoDB.Bson.Serialization.BsonSerializer.RegisterSerializer(
                    new EnumSerializer<MyEnum>(MongoDB.Bson.BsonType.String));

相关内容

最新更新