Сериализация и десериализация производных классов от базового класса - PullRequest
2 голосов
/ 18 октября 2010

Я пытаюсь создать базовый класс, в котором я могу наследовать его (чтобы добавить свойства к производным классам) и использовать методы Load и Save из базового класса. Я снова и снова пишу «Загрузить и сохранить» и хочу применить к нему СУХУЮ ...

namespace Common

{
  using System;
  using System.IO;
  using System.Xml.Serialization;

  public abstract class ApplicationSettings
  {
    protected ApplicationSettings()
    {
    }

    public static ApplicationSettings Load(string fileName)
    {
      if (!File.Exists(fileName))
      {
        return null;
      }

      XmlSerializer serializer = new XmlSerializer(typeof(ApplicationSettings));

      using (StreamReader reader = new StreamReader(fileName))
      {
        ApplicationSettings param = (ApplicationSettings)serializer.Deserialize(reader);
        reader.Close();
        return param;
      }
    }

    public void Save(string fileName)
    {
      XmlSerializer serializer = new XmlSerializer(typeof(ApplicationSettings));
      using (StreamWriter writer = new StreamWriter(fileName))
      {
        serializer.Serialize(writer, this);
        writer.Close();
      }
    }
  }
}

Учитывая этот абстрактный класс, я затем хочу получить класс, такой как:

namespace Common
{
  using System;

  public class ApplicationParameters : ApplicationSettings
  {
    public ApplicationParameters()
    {
    }
    public string AuthorizationCode
    {
      get;
      set;
    }
    public string ReferenceNumber
    {
      get;
      set;
    }
  }
}

Для класса Derived я должен быть в состоянии сделать что-то вроде

Параметры ApplicationParameters = ApplicationParmeters.Load ( "settings.xml");

Однако в приведенной выше реализации возникает ошибка компилятора, когда я пытаюсь привести ApplicationSettings к классу ApplicationParameters, когда я вызываю метод Load в базовом классе.

Есть ли способ сделать это?

Ответы [ 4 ]

3 голосов
/ 18 октября 2010

Попробуйте заменить typeof (ApplicationSettings) на GetType ().

Используя этот механизм, вы также сообщите сериализатору, что ApplicationParameters является дочерним классом ApplicationSettings. Вы делаете это через XmlInclude

[XmlInclude(typeof(ApplicationParameters))]
class ApplicationSettings

Последнее является требованием сериализатора, поскольку в противном случае он не будет знать, какой класс создать.

2 голосов
/ 18 октября 2010

Почему вы используете XmlSerializer?

Если вам не нужно контролировать внешний вид выходного XML, рекомендуется DataContractSerializer

См. здесь , например

1 голос
/ 18 октября 2010

Сделайте класс верхнего уровня универсальным, чтобы методы Save / Load могли поддерживать несколько типов:

public abstract class ApplicationSettings<T>
{
    public static T Load(string xml){ // Implementation }

    public static void Save (T obj) { // Implementation }
}

public class ApplicationParameters : ApplicationSettings<ApplicationParameters>
{
}

Или вы можете просто сделать сами статические методы общими:

public abstract class ApplicationSettings
{
    public static T Load<T>(string xml){ // implementation }

    public static void Save<T>(T obj){ // implementation }
}

Теперь вы заметите, что методы Save / Load из абстрактного родительского класса строго типизированы для дочернего, так что следующая строка будет работать как положено:

ApplicationParameters parameters = ApplicationParameters.Load("settings.xml");

или

ApplicationParameters parameters =
    ApplicationSettings.Load<ApplicationParameters>("settings.xml");

В зависимости от того, какой метод вы используете.

0 голосов
/ 18 октября 2010

Как насчет конструктора в вашем классе ApplicationParameters, который принимает ApplicationSettings в качестве аргумента и копирует общие свойства из одного в другое? А затем просто установите для не разделяемых свойств значение null или значение по умолчанию ...

...