加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-15 21:33:16 所属栏目:百科 来源:网络整理
导读:我正在使用Marc Gravell的 ProtoBuf-net库(r480,net20)来序列化/反序列化包含Dictionary object,object的自定义类.在服务器/客户端场景中使用的已知类型(均为C#). 这将使用BinaryFormatter取代我们当前的方法. 作为基础,我遵循这里提出的建议: protobuf-and
我正在使用Marc Gravell的 ProtoBuf-net库(r480,net20)来序列化/反序列化包含Dictionary< object,object>的自定义类.在服务器/客户端场景中使用的已知类型(均为C#).
这将使用BinaryFormatter取代我们当前的方法.
作为基础,我遵循这里提出的建议:
protobuf-and-listobject-how-to-serialize-deserialize和 protobuf-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模型,但这不是一个开放的保证,它将适用于每个可能设计的模型.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读