【问题标题】:NETJson, how to serialize custom type inside a collection of custom typesNETJson,如何在自定义类型集合中序列化自定义类型
【发布时间】:2016-08-30 09:29:51
【问题描述】:

我应该如何编写这部分代码来序列化所有后代自定义类型?

问题是关于 NETJson (https://github.com/rpgmaker/NetJSON)。

下面是用来测试它的代码。

NETJson 序列化器实现:

class NETJsonFormatter
{
    static bool Initialize()
    {
        NetJSON.NetJSON.IncludeFields = true;
        NetJSON.NetJSON.IncludeTypeInformation = true;
        return true;
    }

    static bool Initialized = Initialize();

    /// <summary>
    /// Serializza un oggetto in un array di byte.
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    [System.Diagnostics.DebuggerStepThrough]
    static public byte[] Serialize(object obj)
    {
        return Encoding.UTF8.GetBytes(NetJSON.NetJSON.Serialize(obj));
    }


    /// <summary>
    /// Trasforma un array di byte nell'oggetto originario.
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    [System.Diagnostics.DebuggerStepThrough]
    static public object Deserialize(byte[] obj)
    {
        return NetJSON.NetJSON.Deserialize<object>(Encoding.UTF8.GetString(obj));
    }


    /// <summary>
    /// Deserializza un array di byte nel Type desiderato.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    static public T Deserialize<T>(byte[] obj)
    {
        return NetJSON.NetJSON.Deserialize<T>(Encoding.UTF8.GetString(obj));
    }
}

要序列化的第一个对象:

[Serializable]
public class ComplexType
{
    public ComplexType()
    {
         this.Numero = 100;
         this.Stringa = "Contenuto";
    }
    public int Numero { get; set; }
    public string Stringa { get; set; }
}

要序列化的第二个对象:

[Serializable]
public class Message_v2 : IMessage
{
    public Message_v2()
    {
        this.Options = new List<string>();
        this.Arguments = new Dictionary<string, object>();
    }

    public bool IsEmpty { get; set; }

    public MessageCommand Command { get; set; }

    public List<string> Options { get; set; }

    /// <summary>
    /// Gli Arguments del parser sono sempre KeyValue. Qual'ora mancasse il Value viene inserito null.
    /// </summary>
    public Dictionary<string, object> Arguments { get; set; }

    /*
     * Public methods
     */

    public void AddOptions(params string[] options)
    {
        foreach (string option in options)
            this.Options.Add(option);
    }

    public void AddArgument(string key, object value)
    {
        this.Arguments.Add(key, value);
    }

    public byte[] ToArray()
    {
        return NETJsonFormatter.Serialize(this);
    }

    public string ToXML()
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// For debugging purposes.
    /// </summary>
    /// <returns></returns>
    public string ToJSON()
    {
        return Encoding.UTF8.GetString(NETJsonFormatter.Serialize(this));
    }

    /*
     * Conversions
     */

    public static explicit operator Message_v2(byte[] source)
    {
        try
        {
            return NETJsonFormatter.Deserialize<Message_v2>(source);
        }
        catch
        {
            return null;
        }
    }
}

以及失败的单元测试。 第一个测试,即 ComplexObject 上的测试,通过了。 为了确保数据一致,我使用 DeepEqual (https://github.com/jamesfoster/DeepEqual - NUGet 上的'DeepEqual'),它提供了用于对象比较的方法 .ShouldDeepEqual。

[TestMethod]
public void CreateAndRetrieveMessage()
{
    ComplexType complexArgument = new ComplexType();

        byte[] serializedComplexArgument = NETJsonFormatter.Serialize(complexArgument);
        ComplexType deserializedComplexArgument = NETJsonFormatter.Deserialize<ComplexType>(serializedComplexArgument);

        deserializedComplexArgument.ShouldDeepEqual(complexArgument);

        /* ------------------------ */

        IMessage message = ProtocolHelper.CreateMessage();
        message.Command = MessageCommand.Set;
        message.AddOptions("keys");
        message.AddArgument("Key1", "Contenuto");
        message.AddArgument("Key2", 100);
        message.AddArgument("Key3", complexArgument);

        // Send over the wire.
        byte[] serialized = message.ToArray();

        // Get the Message sent.
        var deserialized = ProtocolHelper.CreateMessage(serialized);

        deserialized.ShouldDeepEqual(message);
    }

【问题讨论】:

    标签: c# .net json serialization nested


    【解决方案1】:

    来自wiki

    字典 - Value(Object) 支持 Dictionary、IList、Primitive Types 和 Enums

    我认为这是你的问题,只是尝试序列化一个对象字典,它会失败,但是一个 complexType 字典成功......

    ComplexType complexArgument = new ComplexType();
    
    byte[] serializedComplexArgument = NETJsonFormatter.Serialize(complexArgument);
    ComplexType deserializedComplexArgument = NETJsonFormatter.Deserialize<ComplexType>(serializedComplexArgument);
    
    deserializedComplexArgument.ShouldDeepEqual(complexArgument);
    
    
    /* ------------------------ */
    
    var complexTypeDictionnary = new Dictionary<string, ComplexType>();
    complexTypeDictionnary.Add("Key3", complexArgument);
    
    byte[] serializedDic2 = NETJsonFormatter.Serialize(complexTypeDictionnary);
    var deserializeDictionnary2 = NETJsonFormatter.Deserialize<Dictionary<string, ComplexType>>(serializedDic2);
    
    deserializeDictionnary2.ShouldDeepEqual(complexTypeDictionnary); // works
    
    
    /* ------------------------ */
    
    var objectDictionnary = new Dictionary<string, object>();
    objectDictionnary.Add("Key1", "Contenuto");
    objectDictionnary.Add("Key2", 100);
    objectDictionnary.Add("Key3", complexArgument);
    
    byte[] serializedDic = NETJsonFormatter.Serialize(objectDictionnary);
    var deserializeDictionnary = NETJsonFormatter.Deserialize<Dictionary<string, object>>(serializedDic);
    
    deserializeDictionnary.ShouldDeepEqual(objectDictionnary); // doesn't work
    

    编辑

    我曾经使用 NewtonSoft 进行 Json 序列化,也许您正在寻找性能改进或其他,但它适用于它;)

    /* ------------------------ */
    
    var objectDictionnary = new Dictionary<string, object>();
    objectDictionnary.Add("Key1", "Contenuto");
    objectDictionnary.Add("Key2", 100);
    objectDictionnary.Add("Key3", complexArgument);
    
    
    byte[] serializedDicNewton = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject( objectDictionnary));
    var deserializeDictionnaryNewton = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, object>>(Encoding.UTF8.GetString(serializedDicNewton));
    
    deserializeDictionnaryNewton.ShouldDeepEqual(objectDictionnary); // works too
    

    【讨论】:

    • 这听起来不错。但我的问题是我的 Message_v2.Arguments 是动态的,我不知道或控制用户选择输入哪种类型。所以我不能将 Message_v2.Arguments 的声明从 Dictionary 更改为 Dictionary。事实上,在我的单元测试中,我明确写了三个值,一个 int,一个 string,一个 ComplexType。
    • 也许使用其他序列化程序,newtonsoft 非常适合这个用例,我编辑了我的帖子
    • 提高性能是使用 NETJson 的关键。实际上我正在使用 BinaryFormatter 进行序列化并通过线路发送并且运行良好。我已经用 NewtonSoft“玩”过 Json 序列化,完全没有问题。所以,你是对的,如果我想在 Json 上进行序列化,我会使用更“强大”的 json 序列化程序,但我使用标签“NETJson”打开了问题,并且 stackoverflow.com 确实回复了“你不能使用如果您没有 1500 个声望点,请标记 NETJson”。嗯。 :(
    • 您的对象在字典中的类型是真正动态的还是已知类型的子集?如果您知道要使用的不同类型,则可以实现其他逻辑以在具有良好类型的内部字典中分派已知类型,以便序列化可以与 NETJson 一起使用。
    • Dictionary 上的值(引用 Message_v2.Arguments)不在已知类型的子集中。更具体地说,以便您弄清楚将使用哪些类型...我在编写的缓存客户端-服务器项目中使用此类通过 TCP 进行通信,实际上我正在使用 BinaryFormatter 进行序列化。一切正常。字典中包含的类型在运行时是未知的。通信类通过字节序列化并发送到服务器,服务器将其存储并通过字节发送回客户端。即: Dictionary 也不会工作。至少 NETJson 不会。
    【解决方案2】:

    NETJson 没有正确序列化 Dictionary 导致 Object 它是基本类型,但它可以序列化很多原语(包括字节数组)所以我找到了一个解决方案(好吧,现在的解决方法导致我的眼睛流血看着代码 -但效果很好)。

    NETJson 的类助手

    class NETJsonFormatter
    {
        public NETJsonFormatter() { }
    
        static bool Initialize()
        {
            NetJSON.NetJSON.IncludeFields = true;
            NetJSON.NetJSON.IncludeTypeInformation = true;
            return true;
        }
    
        static bool Initialized = Initialize();
    
        /// <summary>
        /// Serializza un oggetto in un array di byte.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        //[System.Diagnostics.DebuggerStepThrough]
        static public byte[] SerializeWithType(object obj)
        {
            return Encoding.UTF8.GetBytes(NetJSON.NetJSON.Serialize(obj.GetType(), obj));
    
        }
    
        /// <summary>
        /// Trasforma un array di byte nell'oggetto originario.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        //[System.Diagnostics.DebuggerStepThrough]
        static public object DeserializeWithType(Type type, byte[] obj)
        {
            return NetJSON.NetJSON.Deserialize(type, Encoding.UTF8.GetString(obj));
        }
    
        static public byte[] Serialize<T>(T obj)
        {
            return Encoding.UTF8.GetBytes(NetJSON.NetJSON.Serialize(obj));
        }
    
        /// <summary>
        /// Deserializza un array di byte nel Type desiderato.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        static public T Deserialize<T>(byte[] obj)
        {
            return NetJSON.NetJSON.Deserialize<T>(Encoding.UTF8.GetString(obj));
        }
    
    }
    

    要序列化的第二个对象(在单元测试中没有成功)

    [Serializable]
    public class Message_v2 //: IMessage
    {
        public Message_v2()
        {
            this.Options = new List<string>();
            this.Arguments = new Dictionary<string, object>();
            this.ValuesForNETJson = new Dictionary<string, byte[]>();
            this.TypesForNETJson = new Dictionary<string, Type>();
        }
    
        public bool IsEmpty { get; set; }
    
        public MessageCommand Command { get; set; }
    
        public List<string> Options { get; set; }
    
        /// <summary>
        /// Gli Arguments del parser sono sempre KeyValue. Qual'ora mancasse il Value viene inserito null.
        /// </summary>
        public Dictionary<string, object> Arguments { get; set; }
    
        /// <summary>
        /// Serializzo gli Arguments in byte array.  
        /// string - Key di Arguments[n]
        /// byte[] - contenuto serializzato di Arguments[n]
        /// </summary>
        public IDictionary<string, byte[]> ValuesForNETJson { get; set; }
        public IDictionary<string, Type> TypesForNETJson { get; set; }
    
        /*
         * Public methods
         */
    
        public void AddOptions(params string[] options)
        {
            foreach (string option in options)
                this.Options.Add(option);
        }
    
        public void AddArgument(string key, object value)
        {
            this.Arguments.Add(key, value);
            this.ValuesForNETJson.Add(key, NETJsonFormatter.SerializeWithType(value));
            this.TypesForNETJson.Add(key, value.GetType());
        }
    
        public byte[] ToArray()
        {
            //this.Arguments.ToDictionary(x => x.Value == null);
            return NETJsonFormatter.Serialize(this);
        }
    
        /*
         * Conversions
         */
    
        public static explicit operator Message_v2(byte[] source)
        {
            try
            {
                Message_v2 message = NETJsonFormatter.Deserialize<Message_v2>(source);
                int count = message.ValuesForNETJson.Count;
                for (int i = 0; i < count; i++)
                {
                    string key = message.Arguments.ElementAt(i).Key;
                    Type type = message.TypesForNETJson.ElementAt(i).Value;
                    byte[] value = message.ValuesForNETJson[key];
                    message.Arguments[key] = NETJsonFormatter.DeserializeWithType(type, value);
                }
                return message;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
    }
    

    我的解决方案肯定会被重新设计,因为它不是最优的,远非如此。 将两个 Dictionary 添加到该类中,使其比使用 ProtoBuf 序列化的同一类增长并更大,并使其变慢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-04
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多