C# – 如何xml反序列化对象本身?
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。 我懒得去财产。 在最高级别上执行将节省大量精力。
如果您的Options类型是结构,这将起作用,因为您可以更改结构本身。
如果Options是一个类(引用类型),则无法在该实例中分配引用类型的当前实例。 建议你编写一个帮助类,并将Read和Save方法放在那里,就像这样
public class XmlSerializerHelper { 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(); var obj=new Options(); //Write and read helper.Save("yourpath",obj); obj=helper.Read("yourpath");
并将XmlSerializerHelper放在Util的命名空间中,它是可重用的,可以使用任何类型。
将.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对象。
根据定义,对象不能反序列化自身:它已经存在,反序列化会创建该类型的新实例。
创建类的新的空实例有时是有意义的,然后用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(); } }
这将确保即使抛出exception也会处理TextReaders。 这就是不再需要近距离通话的原因。
我认为序列化和反序列化对象的最简单方法是使用具有以下两种方法的静态类。 我们还需要一个名为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 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 (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, Encoding.Unicode); //deserialize MyClass myClass2 = GenericXmlSerializer.Deserialize (xml);
我是扩展方法的粉丝,因此我总是使用它:
using System.IO; using System.Xml.Serialization; public static class SerializationExtensionMethods { /// /// Serializes the object. /// /// /// To serialize. /// public static string SerializeObjectToXml(this T toSerialize) { XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType()); StringWriter textWriter = new StringWriter(); xmlSerializer.Serialize(textWriter, toSerialize); return textWriter.ToString(); } /// /// Serializes the object. /// /// /// To serialize. /// The path. public static void SerializeObjectToFile (this T toSerialize, string path) { string xml = SerializeObjectToXml (toSerialize); using (StreamWriter sw = new StreamWriter(path, false)) { sw.Write(xml); } } /// /// Deserializes the specified XML. /// /// /// The XML. /// public static T DeserializeFromXml (this T original, string xml) { XmlSerializer serializer = new XmlSerializer(typeof(T)); TextReader textReader = new StringReader(xml); return (T)serializer.Deserialize(textReader); } /// /// Deserializes the specified object. /// /// /// The original. /// The path. /// public static T DeserializeFromFile (this T original, string path) { string xml = string.Empty; using (StreamReader sr = new StreamReader(path)) { xml = sr.ReadToEnd(); } return DeserializeFromXml (original, xml); } }
用于序列化:
YourClassType obj = new YourClassType();
要么
List obj = new List (); 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 obj = new List ().DeserializeFromFile("XML string here");
要么
YourClassType obj = new YourClassType().DeserializeFromFile("PathToYourFile");
你运行它:)
我更喜欢扩展方法,因为它允许您使代码非常干净,这适用于您拥有的每种对象类型,只要它实现了[Serializable]
属性。
如果需要指定序列化方式(作为节点或属性),可以在每个属性上添加属性,例如:
[XmlElement("NameOfTheElementYouWant")] [XmlAttribute("NameOfTheAttributeYouWant")] [XmlText]
希望这可以帮助将来的某个人。
亚历杭德罗
我采用这种方法(在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");