Вопрос по c# – Как десериализовать сам объект?

8
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 = (Параметры) deserializer.Deserialize (textReader); не будет работать.

Изменить: Любое решение этой проблемы? Можем ли мы достичь той же цели, не назначая этого? То есть десериализовать объект параметров обратно в параметр. Мне лень делать это имущество за имуществом. Выполнение на высшем уровне сэкономит много сил.

Ваш Ответ

7   ответов
5

он уже существует, и десериализация создает новый экземпляр типа.

Иногда имеет смысл создать новый пустой экземпляр класса, а затем заполнить его информацией, полученной из XML. Экземпляр также может быть «почти пустым». Вы можете сделать это, например, чтобы загрузить пользовательские настройки или вообще, чтобы установить экземпляр обратно в прежнее состояние. & Quot; пусто & quot; или "почти пусто" состояние экземпляра было бы допустимым состоянием для класса: он просто не знал бы, в каком состоянии он был до того, как был сохранен.

Кроме того, я рекомендую вам привыкнуть к использованию & quot; блоки:

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 даже в случае возникновения исключения. Вот почему закрывающие вызовы больше не нужны.

Error: User Rate Limit Exceeded david.healed
2

что самый простой способ сериализации и десериализации объекта - это использование статического класса со следующими двумя методами. Нам также нужен класс с именем StringWriterWithEncoding для установки кодировки строки XML, поскольку свойство Encoding стандартного класса StringWriter доступно только для чтения. (найдено здесь: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);
11

если ваш тип 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'а, он будет многократно использоваться и будет работать с любым типом.

Error: User Rate Limit Exceeded david.healed
Error: User Rate Limit Exceeded david.healed
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
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");

Приятное отличие состоит в том, что невозможно когда-либо иметь объект параметров, который не имеет каких-либо данных за ним.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
0

Метод 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");
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

    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")

Это кажется мне приятным и чистым и хорошо работает в моей ситуации.

ура

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]

Надеюсь, это поможет кому-то в будущем.

Alejandro

Похожие вопросы