Сериализация объектов в текстовый файл: какой API / framework? - PullRequest
1 голос
/ 13 мая 2009

Я хочу сохранить объекты DataModel моей программы в файл и снова иметь возможность перезагрузить тот же граф объектов. Я хочу, чтобы он был в какой-то разновидности текстового файла, чтобы я мог его различить и открыть в текстовом редакторе. С XML все будет в порядке, и кажется, что это хорошее место для начала, поскольку в .NET встроена сериализация XML.

Но какой вариант сериализации XML мне выбрать? Я знаю о SoapFormatter (но сейчас он устарел), XamlWriter (красиво, но очень ограниченно), XmlSerializer и DataContractSerializer (ни то, ни другое) Я еще много знаю) (И это только от Microsoft - печаль!) ​​

Я также открыт для фреймворков с открытым исходным кодом и не привязан к XML ( JavaScriptSerializer тоже выглядит интересно).

Некоторые из моих общих предпочтений в рамках сериализации:

  • Мне действительно не нужно писать какой-либо код (или файлы конфигурации XML), чтобы получить вновь добавленное свойство для сериализации. Я мог (неохотно) принять необходимость добавить атрибут, но чем меньше накладных расходов на меня, тем лучше.
  • Соглашение о конфигурации хорошо.
  • Бонусные баллы за все, что может сериализовать граф циклических объектов. Я мог бы избежать этого, если бы мне пришлось, но я бы предпочел не усложнять кодирование только для удобства чьей-либо среды сериализации.
  • Я предпочитаю что-то, что сохраняет значения свойств, а не напрямую попадает в приватные поля.
  • Я бы хотел что-то, что позволяет заглянуть в будущее. Если я переименую свойство или значение перечисления, я не хочу, чтобы мои старые файлы были тостами; Мне нужен какой-то способ определить путь обновления и переназначить значения при загрузке (желательно без записи пакетов файлов конфигурации XML), и я хочу иметь возможность писать автоматические регрессионные тесты, которые доказывают, что я могу открывать старые файлы.
  • Если бы он мог автоматически игнорировать события моих объектов, без необходимости добавлять дополнительные атрибуты к каждому, это было бы замечательно. События никогда не имеют смысла записывать в текстовый формат.
  • Было бы здорово, если бы он работал в Silverlight, а также в полноценном .NET. (У меня нет никакой краткосрочной потребности в этом; это было бы просто круто.)

Предложения

Ответы [ 4 ]

1 голос
/ 13 мая 2009

используйте XmlSerializer или DataContractSerializer, если только они не будут соответствовать вашим требованиям. Могу поспорить, что они могут доставить, и вам больше ничего не понадобится.

1 голос
/ 13 мая 2009

Это большой список требований. Лично я думаю, что DataContractSerializer удовлетворит большинство ваших потребностей.

1) Вы можете добавить свойства, и они будут выбраны автоматически (при условии, что у вас есть .Net 3.5 SP1)

2) Имеется поддержка версий

3) Он существует в Silverlight, хотя в нем отсутствуют некоторые функции, такие как PreserveObjectReferences (я думаю)

4) Вы можете явно определить, что вы хотите сериализовать, так что вы можете исключить ваши личные поля, хотя они будут включены, если вы вообще ничего не укажите.

5) Уверен, он обрабатывает циклические графы объектов, но не цитируйте меня по этому поводу.

1 голос
/ 13 мая 2009

Я думаю, что DataContractSerializer - ваш лучший выбор - это гораздо более современный сериализатор для .NET framework и работает довольно хорошо.

Однако, в интересах справедливости, я бы посоветовал вам прочитать XmlSerializer против DataContractSerializer: сериализация в Wcf для подробного сравнения.

0 голосов
/ 13 мая 2009

Я написал что-то .. надеюсь помочь тебе ..

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

**

этот класс будет сериализовать все свойства READ_WRITE , если свойство не помечено NonSerializedAttribute атрибут

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...