我的班级不会正确序列化

时间:2016-08-23 10:21:38

标签: c# oop dictionary serialization

很抱歉超长问题我不想遗漏任何代码。

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

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()
    {          
    }
}

My 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");

Issue

正如你从上面的图片中看到的那样,在反序列化之后,降低级别的字典似乎丢失了(由空值表示,尽管在序列化之前我检查过它似乎很好。

任何想法?

1 个答案:

答案 0 :(得分:1)

您正在使用BinaryFormatter序列化字典,而不是XmlSerializer,并且为此目的实现了自定义流构造函数和GetObjectData()方法 - 这显然无效。但是,您的基类Dictionary<TKey, TValue> 已经实现了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。如果您需要二进制格式,可以考虑