微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – Protobuf-net:序列化包含Dictionary的自定义类

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

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

>复制字典< object,object>字典< ProtoObject,ProtoObject>在OnSerialising()调用上.
>添加新类型的维护开销(每个类型都需要ProtoInclude标记和ProtoObject.Create(object obj)中的相应强制转换逻辑)
> ProtoObject必须知道所有必需的类型.这会导致项目之间的循环引用问题,这只能通过更大的项目结构重构来解决.

理想情况下,我想使用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();
    }
}

解决方法

序列化字典< object,object>简单来说不是一个支持的用例…我个人认为你应该更多地考虑使用特定于用途的DTO模型,就像使用XmlSerializer,DataContractSerializer或JavascriptSerializer一样. protobuf-net最终仍然是一个合同序列化器,DTO模型是理想的用例.它通常适用于非DTO模型,但这不是一个开放的保证,它将适用于每个可能设计的模型.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐