English 中文(简体)
Protobuf-net: 含有Dictionary <object, 物体的定制类别
原标题:Protobuf-net: serializing a custom class containing a Dictionary<object, object>

I m using Marc Gravell s ProtoBuf-net library (r480, net20) in order to serialize/deserialize a custom class containing a Dictionary<object, object> of known types which is used in a Server/Client scenario (both C#).
This shall replace our current approach using the BinaryFormatter.
As basis I m following the suggestions made here: protobuf-and-listobject-how-to-serialize-deserialize and here protobuf-and-listobject-how-to-serialize-deserialize.

The current approach has some drawbacks though, i hope that somebody more familiar with Protobuf-net can give me a hint on how to improve it.

  1. Copying of Dictionary<object, object> to Dictionary<ProtoObject, ProtoObject> on the OnSerialising() call.
  2. Maintenance overhead on adding new Types (each requiring an ProtoInclude tag and corresponding cast logic in the ProtoObject.Create(object obj))
  3. All required types must be known by ProtoObject. This causes cyclic reference issues between projects, which only could be resolved by a larger refactoring of the project structure.

理想的情况是,我想采用RuntimeTypeModel办法,但我看不出我如何使客户了解这些类型(使客户了解和传送Model型重机?)。

Also in the first topic, Marc Gravell mentioned that upcoming "runtime-extensible schemas" could help, does anyone know if those are implemented yet and how they work?
I m very grateful for whatever response I get, please let me know if I can clarify something more.
Anyway, thanks to Marc Gravell for his fantastic library :).

该法典:

[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();
    }
}
问题回答

缩略语 我认为,你应当更多地研究如何使用特定的DTO模式,如你可能使用<代码>XmlSerializer、<代码>DataContractSerializer或JavascriptSerializer。 它往往与非木材组织模式合作,但这不是一个公开的保证,它将与可能设计的每一种模式合作。





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签