8 Stimmen

C# - Wie zu xml deserialize Objekt selbst?

public class Options
    {
        public FolderOption FolderOption { set; get; }

        public Options()
        {
            FolderOption = new FolderOption();
        }

        public void Save()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Options));
            TextWriter textWriter = new StreamWriter(@"C:\Options.xml");
            serializer.Serialize(textWriter, this);
            textWriter.Close();
        }

        public void Read()
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(Options));
            TextReader textReader = new StreamReader(@"C:\Options.xml");
            //this = (Options)deserializer.Deserialize(textReader);
            textReader.Close();

        }
    }
}

Ich habe es geschafft, ohne Problem zu speichern, alle Mitglieder von FolderOption sind deserialisiert. Aber das Problem ist, wie man es zurücklesen? Die Zeile - //this = (Optionen)deserializer.Deserialize(textReader); wird nicht funktionieren.

Edit: Gibt es eine Lösung für dieses Problem? Können wir den gleichen Zweck ohne Zuweisung zu diesem erreichen? Das ist deserialize Options Objekt zurück in Option. Ich bin zu faul, um es Eigenschaft für Eigenschaft zu tun. Die Ausführung auf der höchsten Ebene würde eine Menge Aufwand sparen.

20voto

Joel Coehoorn Punkte 377088

Bauen Sie Ihr .Read() Methode als statische Funktion, die das gelesene Objekt zurückgibt:

public static Options Read(string path)
{
    XmlSerializer deserializer = new XmlSerializer(typeof(Options));
    using (TextReader textReader = new StreamReader(path))
    {
        return (Options)deserializer.Deserialize(textReader);
    }
}

Ändern Sie dann den aufrufenden Code so, dass er nicht wie folgt aussieht:

Options myOptions = new Options();
myOptions.Read(@"C:\Options.xml");

Sie machen so etwas wie das hier:

Options myOptions = Options.Read(@"C:\Options.xml");

Der schöne Unterschied ist, dass es unmöglich ist, jemals ein Options-Objekt zu haben, das nicht mit Daten hinterlegt ist.

11voto

amazedsaint Punkte 7594

Dies funktioniert, wenn Ihr Optionstyp eine Struktur ist, da Sie eine Struktur selbst ändern können.

Wenn Optionen eine Klasse (Referenztyp) ist, können Sie der aktuellen Instanz eines Referenztyps nicht mit in dieser Instanz zuweisen. Ich schlage Ihnen vor, eine Hilfsklasse zu schreiben und dort Ihre Lese- und Speichermethoden unterzubringen, etwa so

     public class XmlSerializerHelper<T>
    {
        public Type _type;

        public XmlSerializerHelper()
        {
            _type = typeof(T);
        }

        public void Save(string path, object obj)
        {
            using (TextWriter textWriter = new StreamWriter(path))
            {
                XmlSerializer serializer = new XmlSerializer(_type);
                serializer.Serialize(textWriter, obj);
            }

        }

        public T Read(string path)
        {
            T result;
            using (TextReader textReader = new StreamReader(path))
            {
                XmlSerializer deserializer = new XmlSerializer(_type);
                result = (T)deserializer.Deserialize(textReader);
            }
            return result;

        }
    }

Und dann konsumieren Sie es von Ihrem Aufrufer, um Objekte zu lesen und zu speichern, anstatt es von der Klasse aus zu versuchen.

//In the caller

var helper=new XmlSerializerHelper<Options>();
var obj=new Options();

//Write and read
helper.Save("yourpath",obj);
obj=helper.Read("yourpath");

Und legen Sie die XmlSerializerHelper in Ihrem Util Namespace, es ist wiederverwendbar und wird mit jedem Typ arbeiten.

5voto

John Saunders Punkte 159011

Ein Objekt kann sich per Definition nicht selbst deserialisieren: Es existiert bereits, und die Deserialisierung erzeugt eine neue Instanz des Typs.

Manchmal ist es sinnvoll, eine neue, leere Instanz einer Klasse zu erstellen und diese dann mit Informationen aus XML zu füllen. Die Instanz könnte auch "fast leer" sein. Dies könnte man zum Beispiel tun, um Benutzereinstellungen zu laden oder ganz allgemein, um die Instanz wieder so einzurichten, wie sie vorher war. Der "leere" oder "fast leere" Zustand der Instanz wäre ein gültiger Zustand für die Klasse: Sie wüsste nur nicht, in welchem Zustand sie sich befand, bevor sie persistiert wurde.


Außerdem empfehle ich Ihnen, sich anzugewöhnen, Blöcke "zu verwenden":

public void Save()
{
    XmlSerializer serializer = new XmlSerializer(typeof(Options));
    using (TextWriter textWriter = new StreamWriter(@"C:\Options.xml"))
    {
        serializer.Serialize(textWriter, this);
        // no longer needed: textWriter.Close();
    }
}

public void Read()
{
    XmlSerializer deserializer = new XmlSerializer(typeof(Options));
    using (TextReader textReader = new StreamReader(@"C:\Options.xml"))
    {
        // no longer needed: textReader.Close();
    }
}

Dadurch wird sichergestellt, dass die TextReader auch dann entsorgt werden, wenn eine Ausnahme ausgelöst wird. Aus diesem Grund sind die Close-Aufrufe nicht mehr erforderlich.

2voto

Tamás Varga Punkte 21

Ich denke, der einfachste Weg, ein Objekt zu serialisieren und zu deserialisieren, ist die Verwendung einer statischen Klasse mit den folgenden zwei Methoden. Wir brauchen auch eine Klasse namens StringWriterWithEncoding, um die Kodierung der XML-Zeichenfolge festzulegen, da die Eigenschaft Encoding der Standardklasse StringWriter schreibgeschützt ist. (gefunden hier: http://devproj20.blogspot.com/2008/02/writing-xml-with-utf-8-encoding-using.html )

public static class GenericXmlSerializer
{
    public static string Serialize<T>(T obj, Encoding encoding)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));            
        TextWriter textWriter = new StringWriterWithEncoding(new StringBuilder(), encoding);
        serializer.Serialize(textWriter, obj);

        return textWriter.ToString();
    }

    public static T Deserialize<T>(string xml)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        TextReader textReader = new StringReader(xml);
        return (T)serializer.Deserialize(textReader);
    }
}

public class StringWriterWithEncoding : StringWriter
{
    Encoding encoding;

    public StringWriterWithEncoding(StringBuilder builder, Encoding encoding)
        : base(builder)
    {
        this.encoding = encoding;
    }

    public override Encoding Encoding
    {
        get { return encoding; }
    }
}

Verwendung:

//serialize
MyClass myClass = new MyClass();
string xml = GenericXmlSerializer.Serialize<MyClass>(myClass, Encoding.Unicode);

//deserialize
MyClass myClass2 = GenericXmlSerializer.Deserialize<MyClass>(xml);

2voto

coloboxp Punkte 495

Ich bin ein Fan von Erweiterungsmethoden, deshalb verwende ich diese immer:

using System.IO;
using System.Xml.Serialization;

public static class SerializationExtensionMethods
{
    /// <summary>
    /// Serializes the object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="toSerialize">To serialize.</param>
    /// <returns></returns>
    public static string SerializeObjectToXml<T>(this T toSerialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
        StringWriter textWriter = new StringWriter();

        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }

    /// <summary>
    /// Serializes the object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="toSerialize">To serialize.</param>
    /// <param name="path">The path.</param>
    public static void SerializeObjectToFile<T>(this T toSerialize, string path)
    {
        string xml = SerializeObjectToXml<T>(toSerialize);

        using (StreamWriter sw = new StreamWriter(path, false))
        {
            sw.Write(xml);
        }
    }

    /// <summary>
    /// Deserializes the specified XML.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="xml">The XML.</param>
    /// <returns></returns>
    public static T DeserializeFromXml<T>(this T original, string xml)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        TextReader textReader = new StringReader(xml);
        return (T)serializer.Deserialize(textReader);
    }

    /// <summary>
    /// Deserializes the specified object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="original">The original.</param>
    /// <param name="path">The path.</param>
    /// <returns></returns>
    public static T DeserializeFromFile<T>(this T original, string path)
    {
        string xml = string.Empty;

        using (StreamReader sr = new StreamReader(path))
        {
            xml = sr.ReadToEnd();
        }

        return DeserializeFromXml<T>(original, xml);
    }
}

Verwendung zur Serialisierung:

YourClassType obj = new YourClassType();

ou

List<YourClassType> obj = new List<YourClassType>();

string xml = obj.SerializeObjectToXml();

ou

obj.SerializeObjectToFile("PathToYourFile"); // It will save a file with your classes serialized (works with everything with the [Serializable] attribute).

Verwendung zum Deserialisieren:

YourClassType obj = new YourClassType().DeserializeFromXml("XML string here");
List<YourClassType> obj = new List<YourClassType>().DeserializeFromFile("XML string here");

ou

YourClassType obj = new YourClassType().DeserializeFromFile("PathToYourFile");

Und schon läuft es :)

Ich bevorzuge Erweiterungsmethoden, weil sie es Ihnen ermöglichen, Ihren Code sehr sauber zu halten. Dies funktioniert mit jeder Art von Objekttyp, den Sie haben, sofern er die [Serializable] Attribut zugewiesen.

Wenn Sie angeben müssen, wie es serialisiert werden soll (als Knoten oder Attribute), können Sie das Attribut zu jeder Ihrer Eigenschaften hinzufügen, z. B:

[XmlElement("NameOfTheElementYouWant")] 
[XmlAttribute("NameOfTheAttributeYouWant")]
[XmlText]

Ich hoffe, dies hilft jemandem in der Zukunft.

Alejandro

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X