Protobuf-net:序列化包含Dictionary <object,object =“”> </object,>的自定义类

时间:2012-04-20 16:55:44

标签: c# protobuf-net datacontractserializer

我正在使用Marc Gravell的ProtoBuf-net库(r480,net20)来序列化/反序列化包含在服务器/客户端场景中使用的已知类型的词典<object, object>的自定义类( C#) 这将取代我们使用BinaryFormatter的当前方法 作为基础,我遵循这里提出的建议: protobuf-and-listobject-how-to-serialize-deserialize和此处protobuf-and-listobject-how-to-serialize-deserialize

目前的方法有一些缺点,我希望更熟悉Protobuf-net的人可以给我一些提示如何改进它。

  1. 在OnSerialising()调用中将词典<object, object>复制到词典<ProtoObject, ProtoObject>
  2. 添加新类型的维护开销(每个需要ProtoInclude标记和ProtoObject.Create(对象obj)中的相应强制转换逻辑)
  3. ProtoObject必须知道所有必需的类型。这会导致项目之间的循环引用问题,这只能通过更大的项目结构重构来解决。
  4. 理想情况下,我想使用RuntimeTypeModel方法,但我不知道如何让客户端知道类型(编译并将TypeModel dll传输到客户端?)。

    同样在第一个主题中,Marc Gravell提到即将推出的“运行时可扩展模式”可以提供帮助,有人知道这些模式是否已实现以及它们如何工作?
    我非常感谢我得到的任何回复,如果我能澄清更多内容,请告诉我 无论如何,多亏Marc Gravell的神奇图书馆:)。

    以下是代码:

    [Serializable]
    [ProtoContract]
    public class Attributes : IXmlSerializable, IEnumerable, IEquatable<Attributes>, ICloneable
    {
        // Non ProtoBuf-net relevant code was removed
    
        private Dictionary<object, object> attributes = new Dictionary<object, object>();
    
        [ProtoMember(1)]
        private Dictionary<ProtoObject, ProtoObject> protoDictionary;
    
        [OnSerializing]
        public void OnSerializing(StreamingContext context)
        {
            this.protoDictionary = new ProtoDictionary();
    
            foreach (var attribute in attributes)
            {
                this.protoDictionary.Add(ProtoObject.Create(attribute.Key), ProtoObject.Create(attribute.Value));
            }
        }
    
        [OnDeserialized]
        public void OnDeserialized(StreamingContext context)
        {
            if (this.protoDictionary != null)
            {
                this.attributes = new SerializableHashtable();
    
                foreach (var o in this.protoDictionary)
                {
                    this.attributes.Add(o.Key.Value, o.Value.Value);
                }
            }
        }
    }
    
    [ProtoContract]
    [ProtoInclude(1, typeof(ProtoObject<bool>))]
    [ProtoInclude(2, typeof(ProtoObject<byte>))]
    [ProtoInclude(3, typeof(ProtoObject<sbyte>))]
    [ProtoInclude(4, typeof(ProtoObject<ushort>))]
    [ProtoInclude(5, typeof(ProtoObject<short>))]
    [ProtoInclude(6, typeof(ProtoObject<uint>))]
    [ProtoInclude(7, typeof(ProtoObject<int>))]
    [ProtoInclude(8, typeof(ProtoObject<ulong>))]
    [ProtoInclude(9, typeof(ProtoObject<long>))]
    [ProtoInclude(10, typeof(ProtoObject<float>))]
    [ProtoInclude(11, typeof(ProtoObject<double>))]
    [ProtoInclude(12, typeof(ProtoObject<decimal>))]
    [ProtoInclude(13, typeof(ProtoObject<string>))]
    [ProtoInclude(20, typeof(ProtoObject<Vector2F>))]
    [ProtoInclude(21, typeof(ProtoObject<Vector3F>))]
    [ProtoInclude(22, typeof(ProtoObject<Shape>))]
    [ProtoInclude(23, typeof(ProtoObject<SharedUser>))]
    [ProtoInclude(24, typeof(ProtoObject<SharedShip>))]
    //[ProtoInclude(25, typeof(ProtoObject<IVehicleConfiguration>))] // Requires Steering dll -> cyclic reference
    [ProtoInclude(26, typeof(ProtoObject<DroneState>))]
    [ProtoInclude(27, typeof(ProtoObject<BuffCode>))]
    [ProtoInclude(28, typeof(ProtoObject<ItemAttribute>))]
    [ProtoInclude(40, typeof(ProtoObject<List<int>>))]
    public abstract class ProtoObject
    {
        protected ProtoObject()
        {
        }
    
        // Replaces public static ProtoObject<T> Create<T>(T value)
        // in order to use the actual type of the object
        public static ProtoObject Create(object obj)
        {
            if (obj is bool)
            {
                return new ProtoObject<bool>((bool)obj);
            }
    
            if (obj is byte)
            {
                return new ProtoObject<byte>((byte)obj);
            }
    
            // etc. for all required types
    
            return null;
        }
    
        public static ProtoObject Create(bool obj)
        {
            TypeModel.Add(obj.GetType(), true);
    
            return new ProtoObject<bool>(obj);
        }
    
        public static ProtoObject Create(byte obj)
        {
            return new ProtoObject<byte>(obj);
        }
    
        // ... public static ProtoObject Create(type obj) -> for all required types
    
        public object Value
        {
            get { return ValueImpl; }
            set { ValueImpl = value; }
        }
    
        protected abstract object ValueImpl { get; set; }   
    }
    
    [ProtoContract]
    public sealed class ProtoObject<T> : ProtoObject
    {
        public ProtoObject()
        {
        }
    
        public ProtoObject(T value)
        {
            Value = value;
        }
    
        [ProtoMember(1)]
        public new T Value { get; set; }
    
        protected override object ValueImpl
        {
            get { return Value; }
            set { Value = (T)value; }
        }
    
        public override string ToString()
        {
            return Value.ToString();
        }
    }
    

1 个答案:

答案 0 :(得分:1)

序列化Dictionary<object,object>根本不是受支持的用例......就个人而言,我认为您应该更多地考虑使用特定于使用情况的DTO模型,就像使用{{1 },XmlSerializerDataContractSerializer。 protobuf-net最终仍然是一个合同序列化器,DTO模型是理想的用例。它通常适用于非DTO模型,但这不是一个公开的保证,它将适用于每个可能设计的模型。