将对象序列化为文本文件:哪个API /框架?

时间:2009-05-13 01:19:02

标签: .net serialization

我想将程序的DataModel对象保存到文件中,并且能够再次重新加载相同的对象图。我希望它在某种文本文件中,所以我可以将它区分开并在文本编辑器中打开它。 XML很好,而且似乎是一个很好的起点,因为.NET内置了XML序列化。

但我应该选择哪种XML序列化?我知道SoapFormatter(但现在已经弃用了),XamlWriter(很好但非常有限),XmlSerializerDataContractSerializer(我对此都知之甚少)。 (而这只是来自微软的那些 - 好悲伤!)

我也对开源框架持开放态度,而且我不依赖于XML(JavaScriptSerializer看起来也很有趣。)

序列化框架中的一些常规偏好:

  • 我真的不应该编写任何代码(或XML配置文件)来获取新添加的序列化属性。我可以(勉强)接受必须添加一个属性,但是我的开销越少越好。
  • 约定优于配置好。
  • 可以序列化循环对象图的任何内容的加分点。如果必须的话,我可以避免这种情况,但我宁愿不为了方便别人的序列化框架而让我的编码更难。
  • 我更喜欢保存属性值的东西,而不是直接进入私有字段。
  • 我想要一些可以进行未来验证的东西。如果我重命名属性或枚举值,我不希望我的旧文件是吐司;我想要一些方法来定义升级路径并在加载时重新映射值(最好不要编写大量的XML配置文件),我希望能够编写自动回归测试来证明我可以打开旧文件。
  • 如果它可以自动忽略我的对象的事件,而不需要为每个人添加额外的属性,那就太棒了。写入文本格式的事件永远不会有意义。
  • 如果它在Silverlight和完全成熟的.NET中运行,那将是非常酷的。 (我对此没有任何近期需求;它会很酷。)

建议?

4 个答案:

答案 0 :(得分:1)

我认为DataContractSerializer是你最好的选择 - 它是一个更加现代的.NET框架序列化程序并且运行良好。

但是,为了公平起见,我建议您阅读XmlSerializer vs DataContractSerializer: Serialization in Wcf进行详细比较。

答案 1 :(得分:1)

使用XmlSerializer或DataContractSerializer,除非他们无法满足您的要求。我打赌他们可以提供,你不需要别的。

答案 2 :(得分:1)

这是一个很重要的要求清单。就个人而言,我认为DataContractSerializer可以满足您的大部分需求。

1)您可以添加属性,它们将自动被选中(假设您有.Net 3.5 SP1)

2)它有一些版本控制支持

3)它存在于Silverlight中,虽然缺少一些功能,如PreserveObjectReferences(我认为)

4)您可以明确定义要序列化的内容,这样您就可以排除私有字段,但如果您没有指定任何内容,它们将被包含在内。

5)很确定它处理循环对象图,但不要引用我。

答案 3 :(得分:0)

我写了......希望能帮到你..

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

**

如果属性未标记为 NonSerializedAttribute 属性

,则此类将序列化所有READ_WRITE属性

祝你好运!