简体   繁体   English

使用DataContractSerializer序列化大对象图时出现C#StackOverFlowException

[英]C# StackOverFlowException when serializing large object graph with DataContractSerializer

When I try to serialize a huge object graph with DataContractSerializer , I get a StackOverFlowException . 当我尝试使用DataContractSerializer序列化一个巨大的对象图时,出现了StackOverFlowException Increasing stack size to 10 MB fixes the problem in my current scenario, but of course this is not a real solution, as the object graph might be even bigger next time. 将堆栈大小增加到10 MB可以解决当前情况下的问题,但是当然这不是一个真正的解决方案,因为下一次对象图可能会更大。

Is there any other way besides trying to flatten the data structure itself? 除了尝试展平数据结构本身之外,还有其他方法吗? Some parameter telling DataContractSerializer to do breadth first search? 一些参数告诉DataContractSerializer做广度优先搜索? ;-) Any help is greatly appreciated. ;-) 任何帮助是极大的赞赏。 By the way, I use DataContractSerializer because it provides an easy way to keep referential integrity. 顺便说一下,我使用DataContractSerializer是因为它提供了一种保持引用完整性的简便方法。 Keeping this would be nice. 保持这种状态会很好。 :-) :-)

Given that the OP is not using WCF, one possible solution would be to use XmlSerializer class . 鉴于OP没有使用WCF,一种可能的解决方案是使用XmlSerializer class XmlSerializer can help because you have more control and you can use XmlAttributes to reduce the size of the serialized XML string. XmlSerializer可以提供帮助,因为您拥有更多控制权,并且可以使用XmlAttributes减少序列化XML字符串的大小。

I have developed a wrapper for XmlSerializer that uses generics that may be useful - please check the article for more details. 我已经为XmlSerializer开发了一个包装,该包装使用了可能有用的泛型 -请查看本文以获取更多详细信息。 My class can serialize to/from a string or to/from a file. 我的课程可以从字符串或从文件串行化。

Usage: 用法:

Foo foo = ....;
string xml = XmlSerializer<Foo>.Serialize(foo);

XmlSerializer.cs XmlSerializer.cs

/// <summary>
/// XML serializer helper class. Serializes and deserializes objects from/to XML
/// </summary>
/// <typeparam name="T">The type of the object to serialize/deserialize.
/// Must have a parameterless constructor and implement <see cref="Serializable"/></typeparam>
public class XmlSerializer<T> where T: class, new()
{
    /// <summary>
    /// Deserializes a XML string into an object
    /// Default encoding: <c>UTF8</c>
    /// </summary>
    /// <param name="xml">The XML string to deserialize</param>
    /// <returns>An object of type <c>T</c></returns>
    public static T Deserialize(string xml)
    {
        return Deserialize(xml, Encoding.UTF8, null);
    }

    /// <summary>
    /// Deserializes a XML string into an object
    /// Default encoding: <c>UTF8</c>
    /// </summary>
    /// <param name="xml">The XML string to deserialize</param>
    /// <param name="encoding">The encoding</param>
    /// <returns>An object of type <c>T</c></returns>
    public static T Deserialize(string xml, Encoding encoding)
    {
        return Deserialize(xml, encoding, null);
    }

    /// <summary>
    /// Deserializes a XML string into an object
    /// </summary>
    /// <param name="xml">The XML string to deserialize</param>
    /// <param name="settings">XML serialization settings. <see cref="System.Xml.XmlReaderSettings"/></param>
    /// <returns>An object of type <c>T</c></returns>
    public static T Deserialize(string xml, XmlReaderSettings settings)
    {
        return Deserialize(xml, Encoding.UTF8, settings);
    }

    /// <summary>
    /// Deserializes a XML string into an object
    /// </summary>
    /// <param name="xml">The XML string to deserialize</param>
    /// <param name="encoding">The encoding</param>
    /// <param name="settings">XML serialization settings. <see cref="System.Xml.XmlReaderSettings"/></param>
    /// <returns>An object of type <c>T</c></returns>
    public static T Deserialize(string xml, Encoding encoding, XmlReaderSettings settings)
    {
        if (string.IsNullOrEmpty(xml))
            throw new ArgumentException("XML cannot be null or empty", "xml");

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));

        using (MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(xml)))
        {
            using (XmlReader xmlReader = XmlReader.Create(memoryStream, settings))
            {
                return (T) xmlSerializer.Deserialize(xmlReader);
            }
        }
    }

    /// <summary>
    /// Deserializes a XML file.
    /// </summary>
    /// <param name="filename">The filename of the XML file to deserialize</param>
    /// <returns>An object of type <c>T</c></returns>
    public static T DeserializeFromFile(string filename)
    {
        return DeserializeFromFile(filename, new XmlReaderSettings());
    }

    /// <summary>
    /// Deserializes a XML file.
    /// </summary>
    /// <param name="filename">The filename of the XML file to deserialize</param>
    /// <param name="settings">XML serialization settings. <see cref="System.Xml.XmlReaderSettings"/></param>
    /// <returns>An object of type <c>T</c></returns>
    public static T DeserializeFromFile(string filename, XmlReaderSettings settings)
    {
        if (string.IsNullOrEmpty(filename))
            throw new ArgumentException("filename", "XML filename cannot be null or empty");

        if (! File.Exists(filename))
            throw new FileNotFoundException("Cannot find XML file to deserialize", filename);

        // Create the stream writer with the specified encoding
        using (XmlReader reader = XmlReader.Create(filename, settings))
        {
            System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
            return (T) xmlSerializer.Deserialize(reader);
        }
    }

    /// <summary>
    /// Serialize an object
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <returns>A XML string that represents the object to be serialized</returns>
    public static string Serialize(T source)
    {
        // indented XML by default
        return Serialize(source, null, GetIndentedSettings());
    }

    /// <summary>
    /// Serialize an object
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <param name="namespaces">Namespaces to include in serialization</param>
    /// <returns>A XML string that represents the object to be serialized</returns>
    public static string Serialize(T source, XmlSerializerNamespaces namespaces)
    {
        // indented XML by default
        return Serialize(source, namespaces, GetIndentedSettings());
    }

    /// <summary>
    /// Serialize an object
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <param name="settings">XML serialization settings. <see cref="System.Xml.XmlWriterSettings"/></param>
    /// <returns>A XML string that represents the object to be serialized</returns>
    public static string Serialize(T source, XmlWriterSettings settings)
    {
        return Serialize(source, null, settings);
    }

    /// <summary>
    /// Serialize an object
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <param name="namespaces">Namespaces to include in serialization</param>
    /// <param name="settings">XML serialization settings. <see cref="System.Xml.XmlWriterSettings"/></param>
    /// <returns>A XML string that represents the object to be serialized</returns>
    public static string Serialize(T source, XmlSerializerNamespaces namespaces, XmlWriterSettings settings)
    {
        if (source == null)
            throw new ArgumentNullException("source", "Object to serialize cannot be null");

        string xml = null;
        XmlSerializer serializer = new XmlSerializer(source.GetType());

        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream, settings))
            {
                System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
                x.Serialize(xmlWriter, source, namespaces);

                memoryStream.Position = 0; // rewind the stream before reading back.
                using (StreamReader sr = new StreamReader(memoryStream))
                {
                    xml = sr.ReadToEnd();
                } 
            }
        }

        return xml;
    }

    /// <summary>
    /// Serialize an object to a XML file
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <param name="filename">The file to generate</param>
    public static void SerializeToFile(T source, string filename)
    {
        // indented XML by default
        SerializeToFile(source, filename, null, GetIndentedSettings());
    }

    /// <summary>
    /// Serialize an object to a XML file
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <param name="filename">The file to generate</param>
    /// <param name="namespaces">Namespaces to include in serialization</param>
    public static void SerializeToFile(T source, string filename, XmlSerializerNamespaces namespaces)
    {
        // indented XML by default
        SerializeToFile(source, filename, namespaces, GetIndentedSettings());
    }

    /// <summary>
    /// Serialize an object to a XML file
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <param name="filename">The file to generate</param>
    /// <param name="settings">XML serialization settings. <see cref="System.Xml.XmlWriterSettings"/></param>
    public static void SerializeToFile(T source, string filename, XmlWriterSettings settings)
    {
         SerializeToFile(source, filename, null, settings);
    }

    /// <summary>
    /// Serialize an object to a XML file
    /// </summary>
    /// <param name="source">The object to serialize</param>
    /// <param name="filename">The file to generate</param>
    /// <param name="namespaces">Namespaces to include in serialization</param>
    /// <param name="settings">XML serialization settings. <see cref="System.Xml.XmlWriterSettings"/></param>
    public static void SerializeToFile(T source, string filename, XmlSerializerNamespaces namespaces, XmlWriterSettings settings)
    {
        if (source == null)
            throw new ArgumentNullException("source", "Object to serialize cannot be null");

        XmlSerializer serializer = new XmlSerializer(source.GetType());

        using (XmlWriter xmlWriter = XmlWriter.Create(filename, settings))
        {
            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(typeof(T));
            x.Serialize(xmlWriter, source, namespaces);
        }
    }

    #region Private methods


    private static XmlWriterSettings GetIndentedSettings()
    {
        XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
        xmlWriterSettings.Indent = true;
        xmlWriterSettings.IndentChars = "\t";

        return xmlWriterSettings;
    }

    #endregion
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM