【问题标题】:MongoDB serialize Dictionary<MyEnum,object>MongoDB 序列化 Dictionary<MyEnum,object>
【发布时间】:2016-08-27 13:26:00
【问题描述】:

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

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

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

public MyEnum {
  A,
  B
}

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

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

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

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

【问题讨论】:

  • public Dictionary&lt;String, object&gt; MyData { get; set; } 然后你传递 MyEnum.A.toString() 或使用整数。
  • 谢谢,我已经考虑过了,但我正在寻找一个可以轻松添加的通用属性,但我不知道如何做到这一点或一个会议包。

标签: c# mongodb dictionary serialization


【解决方案1】:

问题在于字典序列化程序不会强制键为字符串类型。 要解决这个问题,请创建一个您自己的序列化程序并使用 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();
    }
}

【讨论】:

    【解决方案2】:

    基于@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; }
    

    【讨论】:

    • 这让我获得了MongoDB.Bson.BsonSerializationException: Invalid element: 'FeatureToggleTypeEnum'.。知道可能缺少什么吗?听起来它忽略了密钥的字符串序列化器。
    • 根据需要调整类型。请参阅我的更新答案以获取指针。
    • 感谢您的回复。我这样做了——我只是调整了我的评论的类型,以适应你的例子:)我得到了一个完全普通的枚举类型的异常(手动定义的常量)。
    【解决方案3】:

    这个答案对于评论来说太长了,但它指的是评论。

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

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

    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
    }
    

    【讨论】:

    • 有趣的方法。我想我可以很容易地适应这一点。谢谢。
    猜你喜欢
    • 2017-06-12
    • 2021-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多