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。我懒得去做物业。在最高级别上执行将节省大量精力。
答案 0 :(得分:19)
将.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对象。
答案 1 :(得分:11)
如果您的选项类型是结构,这将起作用,因为您可以更改结构本身。
如果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的命名空间中,它是可重用的,适用于任何类型。
答案 2 :(得分:5)
根据定义,对象无法反序列化:它已经存在,反序列化会创建该类型的新实例。
创建一个新的空类实例有时是有意义的,然后用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。这就是不再需要近距离通话的原因。
答案 3 :(得分:2)
我认为序列化和反序列化对象的最简单方法是使用具有以下两种方法的静态类。我们还需要一个名为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);
答案 4 :(得分:2)
我喜欢扩展方法,因此我总是使用它:
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]
希望这有助于将来。
亚历
答案 5 :(得分:1)
我采用了这种方法(在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")
对我而言似乎很干净,在我的情况下运作良好。
干杯
答案 6 :(得分:0)
请参阅XmlSerializer.Deserialize Method:您可以创建如下的静态方法:
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");