Joe White
Joe White

Reputation: 97708

Serializing objects to a text file: which API/framework?

I want to save my program's DataModel objects to a file, and be able to reload the same object graph again. I want it to be in some flavor of text file, so I can diff it and open it in a text editor. XML would be fine, and seems like a good place to start since .NET has XML serialization built in.

But which flavor of XML serialization should I pick? I know about SoapFormatter (but it's deprecated now), XamlWriter (nice but very limited), XmlSerializer and DataContractSerializer (neither of which I know much about yet). (And that's just the ones from Microsoft - good grief!)

I'm also open to open-source frameworks, and I'm not tied to XML (JavaScriptSerializer looks interesting too).

Some of my general preferences in a serialization framework:

Suggestions?

Upvotes: 1

Views: 1858

Answers (4)

Tolgahan Albayrak
Tolgahan Albayrak

Reputation: 3206

I wrote sth.. hope to help u..

public class TAObjectSerializer
{
    private static void __serializeData(object result, Type propType, XmlWriter wr)
    {
        if (result != null)
        {
            TypeConverter tc = TypeDescriptor.GetConverter(result);
            if (tc != null && tc.CanConvertTo(typeof(string)) && tc.CanConvertFrom(typeof(string)))
            {
                wr.WriteString(tc.ConvertTo(result, typeof(string)) as string);
            }
            else if (propType.IsArray)
            {
                Array tmp = result as Array;
                if (propType.GetElementType() == typeof(object))
                {
                    for (int i = 0; i < tmp.Length; i++)
                    {
                        object v = tmp.GetValue(i);
                        wr.WriteStartElement("item");
                        if (v == null)
                        {
                            wr.WriteAttributeString("type", "");
                        }
                        else
                        {
                            Type vt = v.GetType();
                            wr.WriteAttributeString("type", (vt.IsPrimitive || v is string || v is decimal || v is DateTime || vt.IsArray) ? vt.ToString() : vt.AssemblyQualifiedName);
                            __serializeData(v, v.GetType(), wr);
                        }
                        wr.WriteEndElement();
                    }
                }
                else
                {
                    for (int i = 0; i < tmp.Length; i++)
                    {
                        object v = tmp.GetValue(i);
                        wr.WriteStartElement("item");
                        if (v != null)
                        {
                            __serializeData(v, v.GetType(), wr);
                        }
                        wr.WriteEndElement();
                    }
                }
            }
            else if (propType.IsSerializable)
            {
                using (MemoryStream __ = new MemoryStream())
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(__, result);
                    wr.WriteString(Convert.ToBase64String(__.ToArray()));
                }
            }
            else if (propType.IsClass)
            {
                wr.WriteRaw(__serialize(result));
            }
        }
    }
    private static void __serializeItem(object obj, PropertyInfo pi, XmlWriter wr)
    {
        Type propType = pi.PropertyType;
        object result = pi.GetValue(obj, null);
        wr.WriteStartElement("property");
        wr.WriteAttributeString("type", (propType.IsPrimitive || result is string || result is decimal || result is DateTime || propType.IsArray) ? propType.ToString() : propType.AssemblyQualifiedName);
        wr.WriteAttributeString("name", pi.Name);
        __serializeData(result, propType, wr);
        wr.WriteEndElement();
    }
    private static string __serialize(object obj)
    {
        StringBuilder sb = new StringBuilder();
        XmlWriterSettings set = new XmlWriterSettings();
        set.OmitXmlDeclaration = true;
        using (XmlWriter wr = XmlWriter.Create(sb, set))
        {
            Type t = obj.GetType();
            wr.WriteStartElement("object");
            wr.WriteAttributeString("type", t.AssemblyQualifiedName);
            if (t.IsClass && !(obj is string))
            {
                PropertyInfo[] list = t.GetProperties();
                foreach (PropertyInfo pi in list)
                {
                    if (pi.CanRead && pi.CanWrite && pi.GetCustomAttributes(typeof(NonSerializedAttribute), true).Length == 0)
                    {
                        __serializeItem(obj, pi, wr);
                    }
                }
            }
            wr.WriteEndElement();
        }
        return sb.ToString();
    }
    public static XmlDocument Serialize(object obj)
    {
        if (obj == null)
            throw new ArgumentNullException("obj");
        XmlDocument doc = new XmlDocument();
        string str = __serialize(obj);
        if (!string.IsNullOrEmpty(str))
            doc.LoadXml(str);
        return doc;
    }
    private static object __deserializeItem(Type propType, XmlNode node)
    {
        TypeConverter tc = TypeDescriptor.GetConverter(propType);
        if (tc != null && tc.CanConvertTo(typeof(string)) && tc.CanConvertFrom(typeof(string)))
        {
            return tc.ConvertFrom(node.InnerText);
        }
        else if (propType.IsArray)
        {
            if (propType.GetElementType() == typeof(object))
            {
                XmlNodeList nl = node.SelectNodes("item");
                Array tmp = Array.CreateInstance(typeof(object), nl.Count);
                for (int i = 0; i < nl.Count; i++)
                {
                    XmlNode p = nl[i];
                    Type _t = Type.GetType(p.Attributes["type"].Value);
                    if (_t == null)
                        tmp.SetValue(null, i);
                    else
                        tmp.SetValue(__deserializeItem(_t, p), i);
                }
                return tmp;
            }
            else
            {
                Type _t = propType.GetElementType();
                XmlNodeList nl = node.SelectNodes("item");
                Array tmp = Array.CreateInstance(_t, nl.Count);
                for (int i = 0; i < nl.Count; i++)
                {
                    XmlNode p = nl[i];
                    tmp.SetValue(__deserializeItem(_t, p), i);
                }
                return tmp;
            }
        }
        else if (propType.IsSerializable)
        {
            using (MemoryStream __ = new MemoryStream(Convert.FromBase64String(node.InnerText)))
            {
                BinaryFormatter bf = new BinaryFormatter();
                return bf.Deserialize(__);
            }
        }
        else if (propType.IsClass)
        {
            return __deserialize(node);
        }
        return null;
    }
    private static object __deserialize(XmlNode t)
    {
        try
        {
            object tmp = Activator.CreateInstance(Type.GetType(t.Attributes["type"].Value));
            XmlNodeList nl = t.SelectNodes("property");
            Type objType = tmp.GetType();
            foreach (XmlNode p in nl)
            {
                string name = p.Attributes["name"].Value;
                PropertyInfo pi = objType.GetProperty(name);
                Type propType = Type.GetType(p.Attributes["type"].Value);
                if (propType == pi.PropertyType)
                {
                    pi.SetValue(tmp, __deserializeItem(propType, p), null);
                }
            }
            return tmp;
        }
        catch
        {
        }
        return null;
    }
    public static object Deserialize(XmlDocument doc)
    {
        XmlNode nd = doc.SelectSingleNode("object");
        if (nd == null)
            throw new ArgumentOutOfRangeException();
        return __deserialize(nd);
    }
}

**

Usage :
Serialize : TAObjectSerializer.Serialize(myClassInstance); //this returns as XmlDocument
Deserialize : TAObjectSerializer.Deserialize(myXmlDocument); //this returns as object instance

**

this class will serialize all READ_WRITE properties if property is not marked by NonSerializedAttribute attribute

Good luck!

Upvotes: 0

womp
womp

Reputation: 116977

That's a big list of requirements. Personally, I think that DataContractSerializer would meet most of your needs.

1) You can add properties and they will be picked up automatically (assuming you have .Net 3.5 SP1)

2) It has some versioning support

3) It exists in Silverlight, albeit missing a few features, like PreserveObjectReferences (I think)

4) You can explicitly define what you want serialized, so you can exclude your private fields, although they will be included if you don't specify anything at all.

5) Pretty sure it handles cyclic object graphs, but don't quote me on that.

Upvotes: 1

Cheeso
Cheeso

Reputation: 192477

use XmlSerializer or DataContractSerializer, unless and until they cannot deliver on your requirements. I'm betting they can deliver and you will need nothing else.

Upvotes: 1

Andrew Hare
Andrew Hare

Reputation: 351516

I think the DataContractSerializer is your best bet - it is a much more modern serializer for the .NET framework and works quite well.

However, in the interest of fairness, I would suggest you read XmlSerializer vs DataContractSerializer: Serialization in Wcf for a detailed comparison.

Upvotes: 1

Related Questions