C#-如何对对象本身进行xml反序列化?

C#-如何对对象本身进行xml反序列化?,c#,serialization,C#,Serialization,我成功地保存了FolderOption,所有成员都被反序列化。但问题是如何读回它?行-//this=(选项)反序列化器。反序列化(textReader);不行 编辑:这个问题有什么解决办法吗?我们能在不分配给它的情况下达到同样的目的吗?这就是将选项对象反序列化回选项。我懒得一件一件地做。在最高级别执行将节省大量工作。请参阅:您可以创建如下静态方法: public class Options { public FolderOption FolderOption { set;

我成功地保存了FolderOption,所有成员都被反序列化。但问题是如何读回它?行-//this=(选项)反序列化器。反序列化(textReader);不行

编辑:这个问题有什么解决办法吗?我们能在不分配给它的情况下达到同样的目的吗?这就是将选项对象反序列化回选项。我懒得一件一件地做。在最高级别执行将节省大量工作。

请参阅:您可以创建如下静态方法:

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

        }
    }
}
上述情况可称为:

    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
    }

根据定义,对象无法反序列化自身:它已经存在,反序列化将创建该类型的新实例

有时,创建一个新的空类实例,然后用从XML引入的信息填充它是有意义的。实例也可能“几乎为空”。您可以这样做,例如,为了加载用户首选项,或者一般来说,为了将实例设置回以前的方式。实例的“empty”或“near empty”状态将是类的有效状态:它只是在持久化之前不知道它以前处于什么状态


此外,我建议您养成实现“使用”块的习惯:


这将确保即使引发异常,也会处理TextReader。这就是不再需要关闭调用的原因。

如果您的选项类型是结构,这将起作用,因为您可以更改结构本身

如果选项是一个类(引用类型),则不能将其指定给引用类型的当前实例。建议您编写一个helper类,并将Read和Save方法放在那里,如下所示

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();
    }
}
公共类XmlSerializerHelper
{
公共类型_类型;
公共XMLRHELPER()
{
_类型=类型(T);
}
公共void保存(字符串路径,对象对象对象)
{
使用(TextWriter TextWriter=新StreamWriter(路径))
{
XmlSerializer serializer=新的XmlSerializer(_类型);
serializer.Serialize(textWriter,obj);
}
}
公共T读取(字符串路径)
{
T结果;
使用(文本阅读器文本阅读器=新的流阅读器(路径))
{
XmlSerializer反序列化程序=新的XmlSerializer(_类型);
结果=(T)反序列化程序。反序列化(textReader);
}
返回结果;
}
}
然后从调用方使用它来读取和保存对象,而不是从类中尝试

     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;

        }
    }
//在调用方中
var helper=新的XmlSerializerHelper();
var obj=新选项();
//读写
保存(“yourpath”,obj);
obj=helper.Read(“yourpath”);
并将XmlSerializerHelper放在Util的命名空间中,它是可重用的,可用于任何类型。

.Read()
方法构建为返回读取对象的静态函数:

//In the caller

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

//Write and read
helper.Save("yourpath",obj);
obj=helper.Read("yourpath");
然后更改您的呼叫代码,而不是像这样:

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");
    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
你可以这样做:

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");
    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
很好的区别是,不可能有一个Options对象背后没有数据。

我选择了这种方法(在vb中)

然后,我可以简单地使用如下内容:

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");
    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
这样称呼它:

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");
    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
或者更好(如果我添加必要的构造函数):

对我来说,它看起来很好,很干净,在我的情况下效果很好


干杯

我认为序列化和反序列化对象最简单的方法是使用静态类和以下两种方法。我们还需要一个名为StringWriterWithEncoding的类来设置XML字符串的编码,因为标准StringWriter类的编码属性是只读的。(可在此处找到:)

公共静态类GenericXmlSerializer
{
公共静态字符串序列化(T obj,编码)
{
XmlSerializer serializer=新的XmlSerializer(typeof(T));
TextWriter TextWriter=新StringWriterWithEncoding(新StringBuilder(),encoding);
serializer.Serialize(textWriter,obj);
返回textWriter.ToString();
}
公共静态T反序列化(字符串xml)
{
XmlSerializer serializer=新的XmlSerializer(typeof(T));
TextReader TextReader=新的StringReader(xml);
返回(T)序列化程序。反序列化(textReader);
}
}
公共类StringWriterWithEncoding:StringWriter
{
编码;
公共StringWriterWithEncoding(StringBuilder,Encoding-Encoding)
:基底(建筑商)
{
this.encoding=编码;
}
公共覆盖编码
{
获取{返回编码;}
}
}
用法:

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; }
    }
}
//序列化
MyClass MyClass=新的MyClass();
string xml=GenericXmlSerializer.Serialize(myClass,Encoding.Unicode);
//反序列化
MyClass myClass2=GenericXmlSerializer.Deserialize(xml);

我是扩展方法的粉丝,因此我总是使用以下方法:

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

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

反序列化的用法:

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);
    }
}
obj.SerializeObjectToFile("PathToYourFile"); // It will save a file with your classes serialized (works with everything with the [Serializable] attribute).
您可以让它运行:)

我更喜欢扩展方法,因为它允许您的代码非常干净,这适用于您拥有的每种对象类型,只要它实现了
[Serializable]
属性

如果需要指定如何序列化(作为节点或属性),可以在每个属性上添加属性,例如:

YourClassType obj = new YourClassType().DeserializeFromFile("PathToYourFile");
希望这对将来的人有所帮助


亚历杭德罗请仔细阅读他的问题。2) -1表示不使用“using”块。您仍然需要在XmlReader周围使用-1表示不实现“using”块,以及不使用泛型。使用(XmlSerializer deserializer=new XmlSerializer(_type))不起作用。XmlSerializer未实现IDisposable。正确的答案应该和John的答案一样,将XmlSerializer置于using block之外