views:

64

answers:

4

I am trying to create a base class where I can inherit from it (to add properties to the derived classes) and the utilized the Load and Save methods from the base class. I find myself writing the Load and Save over and over and I'd like to apply some DRY to it...

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

Given this abstract class, I then want to derive a class such as:

namespace Common
{
  using System;

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

For the Derived class, I should be able to do something like

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

However, in the implementation above, an compiler error occurs when I attempt to cast the ApplicationSettings to the ApplicationParameters class when I call the Load method in the base class.

Is there a way to do this?

+2  A: 

Try replacing typeof(ApplicationSettings) with GetType().

Using this mechanism you will also tell the serializer that ApplicationParameters is a child class of ApplicationSettings. You do this via XmlInclude

[XmlInclude(typeof(ApplicationParameters))]
class ApplicationSettings

The latter is a requirements of the serializer because otherwise it won't know what class to instantiate.

Pieter
Yep, that is another way of doing it...good idea
Richard J. Ross III
A: 

How about a constructor in your ApplicationParameters class that takes an ApplicationSettings as an argument and copy the shared properties from one to another? And then just set the not shared properties to be null or the default...

Richard J. Ross III
+1  A: 

Make the top level class generic so that the Save/Load methods can support multiple types:

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

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

public class ApplicationParameters : ApplicationSettings<ApplicationParameters>
{
}

Or you could just make the static methods themselves generic:

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

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

You will now notice that the Save/Load methods from the abstract parent class are strongly typed to the child so that the following line will work as expected:

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

or

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

Depending on which method you use.

Justin Niessner
Using the generic at the class level was exactly what I was trying to do... I also used the GetType() suggestion from another answer but the system will not let me mark both as answers...
Julian Easterling
Also, using the generic at the class level, I moved the "load" into the derived class constructor and then had the constructor call the base Load method... (Thanks, Dave)
Julian Easterling
+1  A: 

Why are you using XmlSerializer ?

Unless you must control the way the output XML looks, DataContractSerializer is recommended

See here, for example

ohadsc
This is an interesting way to go, but puts a requirement of .Net 3.0 as the minimum. I should have stated that, unfortunately, I still have to maintain and write some .Net 2.0 application...
Julian Easterling