2009-05-13 7 views
1

Ich möchte die DataModel-Objekte meines Programms in einer Datei speichern und das gleiche Objektdiagramm erneut laden können. Ich möchte, dass es sich in einer Textdatei befindet, also kann ich es in einem Texteditor öffnen und öffnen. XML wäre in Ordnung und scheint ein guter Startpunkt zu sein, da .NET XML-Serialisierung eingebaut hat.Serialisierung von Objekten in eine Textdatei: Welche API/Framework?

Aber welche Art von XML-Serialisierung sollte ich wählen? Ich weiß über SoapFormatter (aber es ist jetzt veraltet), XamlWriter (nett, aber sehr begrenzt), und DataContractSerializer (von denen ich noch nicht viel darüber weiß). (Und das sind nur die von Microsoft - gute Trauer!)

Ich bin auch offen für Open-Source-Frameworks, und ich bin nicht an XML gebunden (JavaScriptSerializer sieht auch interessant aus).

Einige meiner allgemeinen Präferenzen in einer Serialisierung Rahmen:

  • ich sollte wirklich keine Code (oder XML-Konfigurationsdateien) nicht schreiben müssen, um eine neu hinzugefügte Eigenschaft erhalten zu serialisiert. Ich könnte (widerwillig) akzeptieren, dass ich ein Attribut hinzufügen muss, aber je weniger Overhead bei mir ist, desto besser.
  • Konvention über Konfiguration ist gut.
  • Bonuspunkte für alles, was ein zyklisches Objektdiagramm serialisieren kann. Ich könnte dies vermeiden, wenn ich musste, aber ich würde lieber nicht meine Codierung härter nur für die Bequemlichkeit von jemand anderen Serialisierung Framework.
  • Ich bevorzuge etwas, das Eigenschaftswerte speichert, anstatt direkt in die privaten Felder zu gelangen.
  • Ich möchte etwas, das einige Zukunftssicherheit ermöglicht. Wenn ich eine Eigenschaft oder einen Enum-Wert umbenenne, möchte ich nicht, dass meine alten Dateien Toast sind; Ich möchte einen Upgrade-Pfad definieren und die Werte beim Laden neu zuordnen (vorzugsweise ohne umfangreiche XML-Konfigurationsdateien zu schreiben), und ich möchte in der Lage sein, automatisierte Regressionstests zu schreiben, die beweisen, dass ich alte Dateien öffnen kann.
  • Wenn es die Ereignisse meiner Objekte automatisch ignorieren kann, ohne dass ich jedem zusätzliche Attribute hinzufügen muss, wäre das großartig. Ereignisse würden niemals Sinn machen, in ein Textformat zu schreiben.
  • Es wäre besonders cool, wenn es in Silverlight sowie vollwertige .NET funktionierte. (Ich habe kein kurzfristiges Bedürfnis dafür; es wäre einfach cool.)

Vorschläge?

Antwort

1

Das ist eine große Liste von Anforderungen. Persönlich denke ich, dass DataContractSerializer die meisten Ihrer Bedürfnisse erfüllen würde.

1) Sie können Eigenschaften hinzufügen und diese werden automatisch übernommen (vorausgesetzt, Sie haben .Net 3.5 SP1)

2) Es hat einige Versionierung Unterstützung

3) Es existiert in Silverlight, wenn auch ein paar Features fehlen, wie PreserveObjectReferences (glaube ich)

4) Sie können explizit definieren, was Sie wollen serialisiert, so dass Sie Ihre privaten Felder ausschließen können, obwohl sie eingeschlossen werden, wenn Sie überhaupt nichts angeben.

5) Ziemlich sicher, dass es zyklische Objektdiagramme behandelt, aber zitieren Sie mich nicht darauf.

+0

Hier finden Sie einige gute Informationen zur Versionsunterstützung: Data Contract Versioning http://msdn.microsoft.com/en-us/library/ms731138.aspx, Best Practices: Datenvertragsversionierung http://msdn.microsoft.com/de -us/library/ms733832.aspx. - Joe White vor 26 Sekunden –

+0

Sieht so aus, als ob das Silverlight * PreserveObjectReferences unterstützt (so erhalten Sie zyklische Objektdiagramme). –

1

Verwenden Sie XmlSerializer oder DataContractSerializer, es sei denn, bis sie Ihre Anforderungen nicht erfüllen können. Ich wette, sie können liefern, und Sie werden nichts anderes brauchen.

+0

Aus Erfahrung, wir fanden XmlSerializer nervig, weil es Ihnen nicht erlaubt, private Felder zu serialisieren. Dies führte uns schließlich zur binären Serialisierung (http://msdn.microsoft.com/en-us/library/72hyey7b(VS.71).aspx). DataContractSeraializer scheint dieses Problem gelöst zu haben. Ich muss es noch versuchen. –

0

Ich schrieb etw .. hoffe, u zu helfen ..

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 

**

diese Klasse alle READ_WRITE Eigenschaften wenn Eigenschaft serialisiert werden nicht markiert durch NonSerializedAttribute Attribut

Viel Glück!

+0

Gibt es eine Möglichkeit, bidirektionale Links zu unterstützen? – Pygmy

Verwandte Themen