2
\$\begingroup\$

I'm trying to find a simple, clean and fast way to implement an XML config file in C# without any 3rd party tools. It also should replace this restricted System.Configuration.ConfigurationManager.

using System;
using System.IO;

[Serializable]
public class MyConfigFile
{
    // Static Members
    public static readonly string ConfigFilename = "myConfig.config";
    public static readonly string ConfigFullFilename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), ConfigFilename);

    // Singlton
    private static MyConfigFile _myConfig;
    public static MyConfigFile Instance
    {
        get
        {
            if (_myConfig == null)
            {
                if (!File.Exists(ConfigFullFilename))
                {
                    _myConfig = new MyConfigFile();
                    Save();
                }
                else
                {
                    _myConfig = Load();
                }
            }
            return _myConfig;
        }
    }

    // Constructor
    public MyConfigFile()
    {
        Version = 1;
        ValueA = "Important Value";
        ValueB = DateTime.Now;
        ValueC = false;
    }

    // Properties
    public int Version { get; set; }

    public string ValueA { get; set; }
    public DateTime ValueB { get; set; }
    public bool ValueC { get; set; }

    // Static Methodes
    public static void Save()
    {
        System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(_myConfig.GetType());
        StreamWriter writer = File.CreateText(ConfigFullFilename);
        xs.Serialize(writer, _myConfig);
        writer.Flush();
        writer.Close();
    }

    public static MyConfigFile Load()
    {
        System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(MyConfigFile));
        StreamReader reader = File.OpenText(ConfigFullFilename);
        var c = (MyConfigFile)xs.Deserialize(reader);
        reader.Close();
        return c;
    }
}

This code works fine, but I wonder if you can improve it or have any better ideas.

\$\endgroup\$
2
\$\begingroup\$

Code

  • The StreamReader/StreamWriter in the methods Load and Save should be disposed in a finally block (or better by creating them in a using). Otherwise, the object is not disposed if the serialization/deserialization fails.

  • The method Load does not check if the file exists. If it doesn't, an exception will be thrown. Probably it is enough to make that method private because it is not a required part of the API.

  • Is there any reason for the My prefix? If not, just ConfigFile sounds better to me.

  • Consider to use a more application specific path. For Example SpecialFolders.ApplicationData[CompanyName][Application] for user-specific data or CommonApplicationData[CompanyName][Application] for program-specific data.

API

  • The path of the config file is defined within the class. That has some disadvantages (central configuration is not possible, the class can not be tested by unit tests, the class is not reusable, ...). Therefore, consider to pass the path as constructor argument instead and do not use the singleton pattern.

  • Consider to rename the Instance property to 'Default' or something like that.

  • The methods Save/Load can not be static if the class lost its singleton status - but that should not be a problem.

\$\endgroup\$
  • \$\begingroup\$ Is there any reason for the My prefix? are you really cured? Do you remember this ;-) so many mys \$\endgroup\$ – t3chb0t Sep 26 '16 at 14:03
  • 1
    \$\begingroup\$ @t3chb0t: It's a difference to use my as prefix for instance variables (similar to '_') or as prefix for class names ;) \$\endgroup\$ – JanDotNet Sep 26 '16 at 14:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.