簡體   English   中英

C# - 如何xml反序列化對象本身?

[英]C# - How to xml deserialize object itself?

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();

        }
    }
}

我設法保存沒有問題,FolderOption的所有成員都被反序列化。 但問題是如何閱讀它? 行 - // this =(Options)deserializer.Deserialize(textReader); 不行。

編輯:這個問題的任何解決方案? 我們可以達到同樣的目的而不分配給它嗎? 這是將Options對象反序列化為Option。 我懶得去做物業。 在最高級別上執行將節省大量精力。

.Read()方法構建為返回讀取對象的靜態函數:

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

然后更改您的調用代碼,而不是像這樣:

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

你做這樣的事情:

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

不同的是,不可能有一個沒有一些數據的Options對象。

如果您的Options類型是結構,這將起作用,因為您可以更改結構本身。

如果Options是類(引用類型),則無法在該實例中分配引用類型的當前實例。 建議你編寫一個幫助類,並將Read和Save方法放在那里,就像這樣

     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;

        }
    }

然后從調用者那里使用它來讀取和保存對象,而不是從類中嘗試它。

//In the caller

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

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

並將XmlSerializerHelper放在Util的命名空間中,它是可重用的,可以使用任何類型。

根據定義,對象不能反序列化自身:它已經存在,反序列化會創建該類型的新實例。

創建類的新的空實例有時是有意義的,然后用XML引入的信息填充它。 該實例也可能“幾乎是空的”。 例如,您可以執行此操作以加載用戶首選項,或者通常,將實例重新設置為以前的方式。 實例的“空”或“近空”狀態將是該類的有效狀態:它只是不知道它在持久化之前曾處於什么狀態。


另外,我建議你養成實現“使用”塊的習慣:

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();
    }
}

這將確保即使拋出異常也會處理TextReaders。 這就是不再需要Close調用的原因。

我是擴展方法的粉絲,因此我總是使用它:

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);
    }
}

用於序列化:

YourClassType obj = new YourClassType();

要么

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

string xml = obj.SerializeObjectToXml();

要么

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

用於反序列化:

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

要么

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

你運行它:)

我更喜歡擴展方法,因為它允許你使代碼非常干凈,這適用於你擁有的每種對象類型,只要它實現了它的[Serializable]屬性。

如果需要指定序列化的方式(作為節點或屬性),可以在每個屬性上添加屬性,例如:

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

希望這可以幫助將來的某個人。

亞歷杭德羅

我認為序列化和反序列化對象的最簡單方法是使用具有以下兩種方法的靜態類。 我們還需要一個名為StringWriterWithEncoding的類來設置XML字符串的編碼,因為標准StringWriter類的Encoding屬性是只讀的。 (見於此處: 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; }
    }
}

用法:

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

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

我采用這種方法(在vb中)

    Public Class SerialisableClass

    Public Sub SaveToXML(ByVal outputFilename As String)

        Dim xmls = New System.Xml.Serialization.XmlSerializer(Me.GetType)
        Using sw = New IO.StreamWriter(outputFilename)
            xmls.Serialize(sw, Me)
        End Using

    End Sub

    Private tempState As Object = Me
    Public Sub ReadFromXML(ByVal inputFilename As String)

        Dim xmls = New System.Xml.Serialization.XmlSerializer(Me.GetType)

        Using sr As New IO.StreamReader(inputFilename)
            tempState = xmls.Deserialize(sr)
        End Using

        For Each pi In tempState.GetType.GetProperties()

            Dim name = pi.Name

            Dim realProp = (From p In Me.GetType.GetProperties
                            Where p.Name = name And p.MemberType = Reflection.MemberTypes.Property).Take(1)(0)

            realProp.SetValue(Me, pi.GetValue(tempState, Nothing), Nothing)

        Next

    End Sub

End Class

然后我可以簡單地使用這樣的東西:

Public Class ClientSettings

    Inherits SerialisableClass

    Public Property ZipExePath As String
    Public Property DownloadPath As String
    Public Property UpdateInstallPath As String

End Class

並稱之為:

Dim cs As New ClientSettings
cs.ReadFromXML("c:\myXMLfile.xml")

甚至更好(如果我添加必要的構造函數):

Dim cs as New ClientSettings("c:\myXMLFile.xml")

這對我來說似乎很好,很干凈,在我的情況下運作良好。

干杯

請參閱XmlSerializer.Deserialize方法 :您可以創建如下所示的靜態方法:

    public static Options DeserializeFromFile(string filename) {    
       // Create an instance of the XmlSerializer specifying type and namespace.
       XmlSerializer serializer = new XmlSerializer(typeof(Options));

       // A FileStream is needed to read the XML document.
       using (FileStream fs = new FileStream(filename, FileMode.Open)) {
           XmlReader reader = new XmlTextReader(fs);
           return (Options) serializer.Deserialize(reader);
       } // using
    }

以上可稱為:

 Options foo = Options.DeserializeFromFile(@"C:\Options.xml");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM