繁体   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