【问题标题】:My class wont serialize properly我的课程无法正确序列化
【发布时间】:2016-08-23 10:21:38
【问题描述】:

对不起,我不想遗漏任何代码。

这是加密和序列化的代码……

public class EncryptionSerialiser
{
    byte[] key = {1, 2, 3, 4, 5, 6, 7, 8}; // Where to store these keys is the tricky part, 
    // you may need to obfuscate them or get the user to input a password each time
    byte[] iv = {1, 2, 3, 4, 5, 6, 7, 8};
    //string path = Application.StartupPath + @"\" + "test.ser";
    DESCryptoServiceProvider des = new DESCryptoServiceProvider();

    public void EncryptThenSerialise(object obj, string pathandfilename)
    {
        // Encryption
        using (var fs = new FileStream(pathandfilename, FileMode.Create, FileAccess.Write))
        using (var cryptoStream = new CryptoStream(fs, des.CreateEncryptor(key, iv), CryptoStreamMode.Write))
        {
            BinaryFormatter formatter = new BinaryFormatter();

            // This is where you serialize the class
            try
            {
                formatter.Serialize(cryptoStream, obj);
            }
            catch (Exception ex)
            {
                // MessageBox.Show(ex.ToString());
            }
            //  cryptoStream.Close();
        }
    }

    public T DecryptThenDeSerialise<T>(object obj, string pathandfilename)
    {
        // Decryption
        using (var fs = new FileStream(pathandfilename, FileMode.Open, FileAccess.Read))
        using (var cryptoStream = new CryptoStream(fs, des.CreateDecryptor(key, iv), CryptoStreamMode.Read))
        {
            BinaryFormatter formatter = new BinaryFormatter();

            // This is where you deserialize the class
            T deserialized = (T) formatter.Deserialize(cryptoStream);

            return deserialized;
        }
    }

我的高级词典课程...

[Serializable]
public class HighLevelDictionary : SerializableDictionary<string, LowLevelDictionary>
{
    protected HighLevelDictionary(SerializationInfo info, StreamingContext context)
    {
        int itemCount = info.GetInt32("ItemCount");
        for (int i = 0; i < itemCount; i++)
        {
            KeyValuePair<string,  LowLevelDictionary> kvp =
                (KeyValuePair<string, LowLevelDictionary>)
                info.GetValue(String.Format("Item{0}", i),
                    typeof(KeyValuePair<string,  LowLevelDictionary

            this.Add(kvp.Key, kvp.Value);
        }
    }

    public HighLevelDictionary()
    {          
    }
}

我的 LowlevelDictionary 类...

[Serializable]
public class LowLevelDictionary : SerializableDictionary<string, decimal>
{
    protected LowLevelDictionary(SerializationInfo info, StreamingContext context)
    {
        int itemCount = info.GetInt32("ItemCount");
        for (int i = 0; i < itemCount; i++)
        {
            KeyValuePair<string, decimal> kvp =
                (KeyValuePair<string, decimal>)
                info.GetValue(String.Format("Item{0}", i),
                    typeof(KeyValuePair<string, decimal>));

            this.Add(kvp.Key, kvp.Value);
        }
    }

    public LowLevelDictionary()
    {
    }
}

我的可序列化 SerializableDictionary 类...

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;

[Serializable()]
public class SerializableDictionary<TKey, TVal> : Dictionary<TKey, TVal>, IXmlSerializable, ISerializable
{
    #region Constants
    private const string DictionaryNodeName = "Dictionary";
    private const string ItemNodeName = "Item";
    private const string KeyNodeName = "Key";
    private const string ValueNodeName = "Value";
    #endregion
    #region Constructors
    public SerializableDictionary()
    {
    }

    public SerializableDictionary(IDictionary<TKey, TVal> dictionary)
        : base(dictionary)
    {
    }

    public SerializableDictionary(IEqualityComparer<TKey> comparer)
        : base(comparer)
    {
    }

    public SerializableDictionary(int capacity)
        : base(capacity)
    {
    }

    public SerializableDictionary(IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer)
        : base(dictionary, comparer)
    {
    }

    public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
        : base(capacity, comparer)
    {
    }

    #endregion
    #region ISerializable Members

    protected SerializableDictionary(SerializationInfo info, StreamingContext context)
    {
        int itemCount = info.GetInt32("ItemCount");
        for (int i = 0; i < itemCount; i++)
        {
            KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format("Item{0}", i), typeof(KeyValuePair<TKey, TVal>));
            this.Add(kvp.Key, kvp.Value);
        }
    }

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("ItemCount", this.Count);
        int itemIdx = 0;
        foreach (KeyValuePair<TKey, TVal> kvp in this)
        {
            info.AddValue(String.Format("Item{0}", itemIdx), kvp, typeof(KeyValuePair<TKey, TVal>));
            itemIdx++;
        }
    }

    #endregion
    #region IXmlSerializable Members

    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
    {
        //writer.WriteStartElement(DictionaryNodeName);
        foreach (KeyValuePair<TKey, TVal> kvp in this)
        {
            writer.WriteStartElement(ItemNodeName);
            writer.WriteStartElement(KeyNodeName);
            KeySerializer.Serialize(writer, kvp.Key);
            writer.WriteEndElement();
            writer.WriteStartElement(ValueNodeName);
            ValueSerializer.Serialize(writer, kvp.Value);
            writer.WriteEndElement();
            writer.WriteEndElement();
        }
        //writer.WriteEndElement();
    }

    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
    {
        if (reader.IsEmptyElement)
        {
            return;
        }

        // Move past container
        if (!reader.Read())
        {
            throw new XmlException("Error in Deserialization of Dictionary");
        }

        //reader.ReadStartElement(DictionaryNodeName);
        while (reader.NodeType != XmlNodeType.EndElement)
        {
            reader.ReadStartElement(ItemNodeName);
            reader.ReadStartElement(KeyNodeName);
            TKey key = (TKey)KeySerializer.Deserialize(reader);
            reader.ReadEndElement();
            reader.ReadStartElement(ValueNodeName);
            TVal value = (TVal)ValueSerializer.Deserialize(reader);
            reader.ReadEndElement();
            reader.ReadEndElement();
            this.Add(key, value);
            reader.MoveToContent();
        }
        //reader.ReadEndElement();

        reader.ReadEndElement(); // Read End Element to close Read of containing node
    }

    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
    {
        return null;
    }

    #endregion
    #region Private Properties
    protected XmlSerializer ValueSerializer
    {
        get
        {
            if (valueSerializer == null)
            {
                valueSerializer = new XmlSerializer(typeof(TVal));
            }
            return valueSerializer;
        }
    }

    private XmlSerializer KeySerializer
    {
        get
        {
            if (keySerializer == null)
            {
                keySerializer = new XmlSerializer(typeof(TKey));
            }
            return keySerializer;
        }
    }
    #endregion
    #region Private Members
    private XmlSerializer keySerializer = null;
    private XmlSerializer valueSerializer = null;
    #endregion
}

我的测试代码...

EncryptionSerialiser encryptionSerialiser = new EncryptionSerialiser();

GlobalApplicationSettings globalApplicationSettings = new GlobalApplicationSettings();
// CurrentSingleValueOperation.Save();

HighLevelDictionary highLevelDictionary = new HighLevelDictionary();

LowLevelDictionary lowLevelDictionary = new LowLevelDictionary();
lowLevelDictionary.Add("S1", 0.00m);
lowLevelDictionary.Add("S2", 0.00m);

LowLevelDictionary lowLevelDictionary2 = new LowLevelDictionary();
lowLevelDictionary2.Add("S1", 4.00m);
lowLevelDictionary2.Add("S2", 4.00m);

highLevelDictionary.Add("One", lowLevelDictionary);
highLevelDictionary.Add("tWO", lowLevelDictionary2);

encryptionSerialiser.EncryptThenSerialise(highLevelDictionary,
    globalApplicationSettings.PriceSetsFullPath + "SVO0.crypt");

HighLevelDictionary extraHighLevelDictionary = new HighLevelDictionary();

extraHighLevelDictionary = encryptionSerialiser.DecryptThenDeSerialise<HighLevelDictionary>(extraHighLevelDictionary,
    globalApplicationSettings.PriceSetsFullPath + "SVO0.crypt");

从上图中可以看出,在反序列化后,降低级别的字典内容似乎丢失了(由 null 值表示,尽管在序列化之前我检查了它似乎很好。

有什么想法吗?

【问题讨论】:

  • HighLevelDictionary 的构造函数是私有的。尝试公开。
  • 感谢您的建议,它不是私有的,而是受保护的,我尝试将其设为私有仍然没有用。
  • 尝试禁用加密,看看是否正确序列化
  • @slawekwin 禁用了加密,但仍然失败。

标签: c# oop dictionary serialization


【解决方案1】:

您对该问题的最后评论指出,您的实现适用于xml 序列化,但不适用于您在EncryptionSerialiser 类中使用的BinaryFormatter。这是这里的关键信息。

请注意,SerializableDictionary 基类中的序列化实现基于实现IXmlSerializable 接口。 This interfaceXmlSerializer 调用,但不被二进制序列化使用。我猜想更高级别的Dictionary 是默认序列化的,因为Serializable 属性。

您必须为二进制方法实现合适的接口。我会从this开始

【讨论】:

    【解决方案2】:

    您正在使用BinaryFormatter 来序列化您的字典,而不是XmlSerializer,并且为此目的实现了自定义流构造函数和GetObjectData() 方法——这显然不起作用。但是,您的基类Dictionary&lt;TKey, TValue&gt;已经实现了ISerializable,因此它已经拥有自己的streaming constructorGetObjectData() 方法。与其尝试创建自己的这些方法版本,不如直接使用它们,它们会起作用:

    [Serializable]
    public class HighLevelDictionary : SerializableDictionary<string, LowLevelDictionary>
    {
        public HighLevelDictionary()
        {
        }
    
        protected HighLevelDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }
    
    [Serializable]
    public class LowLevelDictionary : SerializableDictionary<string, decimal>
    {
        protected LowLevelDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
    
        public LowLevelDictionary()
        {
        }
    }
    
    [Serializable()]
    public class SerializableDictionary<TKey, TVal> : Dictionary<TKey, TVal>, IXmlSerializable
    {
        #region Constructors
        public SerializableDictionary()
        {
        }
    
        public SerializableDictionary(IDictionary<TKey, TVal> dictionary)
            : base(dictionary)
        {
        }
    
        public SerializableDictionary(IEqualityComparer<TKey> comparer)
            : base(comparer)
        {
        }
    
        public SerializableDictionary(int capacity)
            : base(capacity)
        {
        }
    
        public SerializableDictionary(IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer)
            : base(dictionary, comparer)
        {
        }
    
        public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
            : base(capacity, comparer)
        {
        }
    
        #endregion
    
        #region ISerializable members
    
        protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }
    
        #endregion
    
        #region Constants
        private const string DictionaryNodeName = "Dictionary";
        private const string ItemNodeName = "Item";
        private const string KeyNodeName = "Key";
        private const string ValueNodeName = "Value";
        #endregion
    
        #region IXmlSerializable Members
    
        void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
        {
            //writer.WriteStartElement(DictionaryNodeName);
            foreach (KeyValuePair<TKey, TVal> kvp in this)
            {
                writer.WriteStartElement(ItemNodeName);
                writer.WriteStartElement(KeyNodeName);
                KeySerializer.Serialize(writer, kvp.Key);
                writer.WriteEndElement();
                writer.WriteStartElement(ValueNodeName);
                ValueSerializer.Serialize(writer, kvp.Value);
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
            //writer.WriteEndElement();
        }
    
        void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
        {
            if (reader.IsEmptyElement)
            {
                return;
            }
    
            // Move past container
            if (!reader.Read())
            {
                throw new XmlException("Error in Deserialization of Dictionary");
            }
    
            //reader.ReadStartElement(DictionaryNodeName);
            while (reader.NodeType != XmlNodeType.EndElement)
            {
                reader.ReadStartElement(ItemNodeName);
                reader.ReadStartElement(KeyNodeName);
                TKey key = (TKey)KeySerializer.Deserialize(reader);
                reader.ReadEndElement();
                reader.ReadStartElement(ValueNodeName);
                TVal value = (TVal)ValueSerializer.Deserialize(reader);
                reader.ReadEndElement();
                reader.ReadEndElement();
                this.Add(key, value);
                reader.MoveToContent();
            }
            //reader.ReadEndElement();
    
            reader.ReadEndElement(); // Read End Element to close Read of containing node
        }
    
        System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
        {
            return null;
        }
    
        #endregion
        #region Private Properties
        protected XmlSerializer ValueSerializer
        {
            get
            {
                if (valueSerializer == null)
                {
                    valueSerializer = new XmlSerializer(typeof(TVal));
                }
                return valueSerializer;
            }
        }
    
        private XmlSerializer KeySerializer
        {
            get
            {
                if (keySerializer == null)
                {
                    keySerializer = new XmlSerializer(typeof(TKey));
                }
                return keySerializer;
            }
        }
        #endregion
        #region Private Members
        private XmlSerializer keySerializer = null;
        private XmlSerializer valueSerializer = null;
        #endregion
    }
    

    示例fiddle

    话虽如此,BinaryFormatter 并不是持久化数据的好选择。参见例如What are the deficiencies of the built-in BinaryFormatter based .Net serialization?Assembly Independent Serialization in .NETXmlSerializer 是一种明显的选择,因为您已经实现了 IXmlSerializable。如果您需要二进制格式,可以考虑

    【讨论】:

      猜你喜欢
      • 2012-02-12
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      • 2016-04-15
      相关资源
      最近更新 更多