MongoDB 序列化 Dictionary<MyEnum,object>

Dem*_*nia 7 c# serialization dictionary mongodb

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

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

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

public MyEnum {
  A,
  B
}

[BsonDictionaryOptions(DictionaryRepresentation.Document)]
public Dictionary<MyEnum, object> MyData { get; set; }
Run Code Online (Sandbox Code Playgroud)

由于不同的原因,我想在 mongo 中拥有类似的东西。

{
   "MyData": {
      "B": "xxxx",
      "A": "xxxx"
   }
}
Run Code Online (Sandbox Code Playgroud)

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

小智 5

问题是字典序列化器不会强制键为字符串类型。要解决此问题,请创建您自己的序列化程序并使用 BsonSerializer 属性选择它。

public class EnumDictionarySerializer<TKey, TDictionary> : DictionarySerializerBase<TDictionary> 
    where TKey : struct
    where TDictionary : class, IDictionary, new()
{
    public EnumDictionarySerializer():base(DictionaryRepresentation.Document, new EnumSerializer<TKey>(BsonType.String), new ObjectSerializer())
    {

    }

    protected override TDictionary CreateInstance()
    {
        return new TDictionary();
    }
}
Run Code Online (Sandbox Code Playgroud)


Bou*_*uke 5

基于@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) { }
}
Run Code Online (Sandbox Code Playgroud)

像这样的用法,其中键和值都是枚举类型,但可以是任何类型:

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


Tom*_*zak 2

这个答案对于评论来说太长了,但它引用了一条评论。

这需要在程序运行时进行反射来更改该对象的类型。起初这是一个非常糟糕的主意,其次这会非常慢。

我建议您为此目的使用字典实现或使用扩展类:

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...
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)