views:

1012

answers:

4

I have a console application that I am rebuilding from C to C#. This application has to be able to support the legacy method of storing information like parameters from a command-line and parameters from a file (called the system parameters) that customize each run. The system parameters file is in plain-text with a simple key : value structure.

My questions are:

  • Should I combine these different parameters into a single Configuration object?
  • How would I call this configuration object from the code to store parameters?
  • How would I call this configuration object from the code to retrieve parameters?
    • Should this object be strongly-typed?
  • I will need access to this structure from a lot of different places in the code, what is the most elegant way to retrieve the values in the object without passing the object itself around everywhere?

I have a feeling that it should be a single, strongly-typed object and that it should be an instantiated object that is retrieved from a repository with a static retrieval method however I really want validation of this method.

Thanks in advance

+5  A: 

I like using Settings. These can be generated automatically either by creating a Settings File using the Add New File dialog box, or by adding a default Settings File from Project Properties. Each setting may be in User or Application scope, which controls whether or not the user can change them or they are restricted to their default values. They are easily saved with the Save() method and loaded automatically into the static Default property.

This class seems to be for application or user-based settings. I'm looking for per-run settings. Would you still recommend using this class in that case? – x97mdr

Yes. If you have both user/application based settings and per-run settings you should use two different classes - the normal (saved) settings and the per-run settings. As long as you don't save the per-run settings, you should be safe and settings are still quite easy to use. These are static settings though. If the same application run needs several instances - this is the wrong approach.

configurator
This class seems to be for application or user-based settings. I'm looking for per-run settings. Would you still recommend using this class in that case?
Jeffrey Cameron
Yes - see my elaboration in the edit.
configurator
A: 

XmlDocument - you can generate a class definition using XSD.exe

Jason
+1  A: 

I find that whenever I have to deal with a legacy system, sticking with the old format almost always works best. Often times there are other people using the legacy formats for other tasks (like automation of the app, for example), so if you recode the way the application handles inputs, you might break other systems.

On the other hand, if you are pretty confident that you know all the people using the system, and they tell you that they don't care if you change these types of things, I would probably move everything to XML. Besides all the nice features of XML from an application point of view (like being in ASCII so it's easily modified by humans, being self-documenting, etc ...), XML is also time-saving, in that you don't have to write your own I/O or parser. There's already a wide variety of libraries out there, particularly in .NET 3.0/3.5, that do very well. (As you're moving to C#, I'm guessing you're already thinking along these lines :)

So ultimately, you'd have to base your decision on cost-to-implement: if you lower your cost of implementation by moving to XML or similar, make sure that you don't raise other people's cost of implementation to move to your new application framework.

Good luck!

Mike
I have to be able to support the legacy format for now. I would like to move to XML in the future though. What do you think of the Settings class as described above?
Jeffrey Cameron
+2  A: 

I would use a single configuration object like the following:

using System;
using System.IO;
using System.Reflection;
public sealed class Setting {
  public static int FrameMax { get; set; }
  public static string VideoDir { get; set; }
  static readonly string SETTINGS = "Settings.ini";
  static readonly Setting instance = new Setting();
  Setting() {}
  static Setting() {
    string property = "";
    string[] settings = File.ReadAllLines(SETTINGS);
    foreach (string s in settings)
      try {
        string[] split = s.Split(new char[] { ':' }, 2);
        if (split.Length != 2)
          continue;
        property = split[0].Trim();
        string value = split[1].Trim();
        PropertyInfo propInfo = instance.GetType().GetProperty(property);
        switch (propInfo.PropertyType.Name) {
          case "Int32":
            propInfo.SetValue(null, Convert.ToInt32(value), null);
            break;
          case "String":
            propInfo.SetValue(null, value, null);
            break;
        }
      } catch {
        throw new Exception("Invalid setting '" + property + "'");
      }
  }
}

Since this is a singleton, it will create one and only one instance of itself the first time a public static property is referenced from the Setting object.

When the object is created, it reads from the Settings.ini file. The settings file is a plain-text file with a simple key : value structure that might look like this:

FrameMax : 12
VideoDir : C:\Videos\Best

The object uses reflection to discover each property and to store its initial value. In this example, two properties have been defined:

 public static int FrameMax { get; set; }
 public static string VideoDir { get; set; }

The code as written handles Int32 and String types. By adding additional case statements to the switch statement, you could easily add support for types like Float and Decimal.

To change a setting, you would use something like:

Setting.FrameMax = 5;

To retrieve a setting, you would use something like:

if (Setting.FrameMax > 10) ...

You'll notice that all the properties are strongly-typed. Also, you don't have to pass the Setting object around, as all the Setting properties are static and always available everywhere.

I hope this idea is helpful.

Protagonist