5

EDIT: I've done some research about this, but have not been able to find a solution!

I'm reading a configuration from an XML file. The layout of the configuration is set for certain version. This version is in the first line of the XML, which is easy to extract.

What I would like to know is, what is the best way to actually parse this file/get another method, based on the version (so all 4 elements, the Major, Minor, Build and Revision).

Right now I've come up with this:

switch (version.Major)
{
    case 0:
        switch (version.Minor)
        {
            case 0:
                switch (version.Build)
                {
                    case 0:
                        switch (version.Revision)
                        {
                            case 0:
                                return VersionNone(doc);
                        }
                        break;
                }
                break;
        }
        break;
}
throw new NotImplementedException();

But I do not find this elegant (at all) and I feel like there is a way better way to do this.

Anyone who can help?

Foitn
  • 604
  • 6
  • 25

4 Answers4

8

For something like this i'd be tempted to build a dictionary of actions

Edit: Updated to include a document paramter in response to comment from OP

    Dictionary<string, Action<XmlDocument>> versionSpecificMethods = new Dictionary<string, Action<XmlDocument>>{
    {"1.0.0.0", DoStuff1},
    {"1.2.3.4", DoStuff2},
    {"3.1.7.182", DoStuff3}};

    private void RunMethodForVersion(string version, XmlDocument someXmlDoc)
    {
        var codeToRun = versionSpecificMethods[version];
        codeToRun.Invoke(someXmlDoc);
    }

    private static void DoStuff1(XmlDocument doc)
    {
        // Insert user code here
    }
Andy P
  • 667
  • 7
  • 14
  • 1
    This looks good, but I might parse the string using the [Version](https://msdn.microsoft.com/en-us/library/system.version(v=vs.110).aspx) class. Will allow for the comparing of the Major,Minor,Build,Revision numbers based on the question's example. – Issa Fram Mar 30 '18 at 01:08
  • Woaw, thanks, that looks a lot more like it. Though, Would this allow for me to pass a doc parameter into the action? Can you maybe give an example too of the DoStuff? – Foitn Mar 30 '18 at 06:42
  • @Foitn Yes, you can absolutely include a parameter for an Action. I've updated the example to take an XmlDocument as a parameter, and included a method stub for 'DoStuff' – Andy P Mar 30 '18 at 10:56
  • @AndyP Alright, thats almost what I need, one last thing I should have mentioned before is, how do I return this to my function? Am I able to call "var x = codeToRun.Invoke(someXmlDoc);" and have the parsed object in "x"? – Foitn Mar 30 '18 at 11:09
  • @Foitn To get a return value, you would use 'Func' (https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx) instead of 'Action'. – Andy P Mar 30 '18 at 11:25
3

If you want to share code between version, you can try to use inheritance:

interface IConfig 
{
     string GetConnectionString();
     string GetUserSettings();
     int GetDelay();
}

class Version_1 : IConfig
{
     public virtual string GetConnectionString() { ... }
     public virtual string GetUserSettings { ... }
     public virtual int GetDelay();
}

class Version_1_1 : Version_1
{
    // Changed UserSetttings and delay in xml
    public override GetUserSettings { ... }
    public override int GetDelay { ... }
}

class Version_1_1_4 : Version_1_1
{
    // Changed delay in xml
    public override int GetDelay { ... }
}

Now you need create reqired instance of config depend on version of your file.

Sergei Shvets
  • 1,676
  • 1
  • 14
  • 12
  • I suppose you would use Reflection to find the proper class? – Foitn Mar 30 '18 at 11:09
  • You can create list of all interface implementations by hand or automatically (https://stackoverflow.com/questions/26733/getting-all-types-that-implement-an-interface). Sort by type name, split by '_' and find apropriate version. – Sergei Shvets Apr 02 '18 at 02:00
2

You can try this e.g :(

enum Version {
    Major = 0,
    Build = 1,
    Revision = 2
}
public class MyApp {
    static Dictionary<Version, object> versionManager = new Dictionary<Version, object> {
        {Version.Major, new Major() },
        {Version.Build, new Build() },
        {Version.Revision, new Revision() }
    };

    public static object Run( int v, XmlDocument xmlDoc ) {
        try {
            Version version = (Version)v;
            var classObj = versionManager[version];
            return classObj.GetType().GetMethod("Parse").Invoke(classObj, new object[] { xmlDoc });//System.Reflection;
        } catch {
            throw new NotImplementedException();
        }
    }
}
//Major = 0
class Major {
    public Major( ) { }
    public string Parse( XmlDocument xmlDoc ) {
        return "DONE";
    }
}
//Build = 1
class Build {
    public Build( ) { }
    public string Parse( XmlDocument xmlDoc ) {
        return "DONE";
    }
}
//Revision = 2
class Revision {
    public Revision( ) { }
    public string Parse( XmlDocument xmlDoc ) {
        return "DONE";
    }
}

Use ==>

MyApp.Run(1/*Version==>Build*/, new XmlDocument());
Rajib Chy
  • 800
  • 10
  • 22
1

Based on @Andy-P's answer, but looks for 'most recent' version instead of exact version:

using ParserFunction = System.Func<object,object>;

public static class ParserFactory
{

    private static System.Collections.Generic.SortedDictionary<Version, ParserFunction> Parsers
        = new System.Collections.Generic.SortedDictionary<Version, ParserFunction>();

    public static void SetParser(Version version, ParserFunction parser)
    {
        if (Parsers.ContainsKey(version)) Parsers[version] = parser;
        else Parsers.Add(version, parser);
    }

    public static ParserFunction GetParser(Version version)
    {
        if (Parsers.Count == 0) return null;

        Version lastKey = null;

        foreach ( var key in Parsers.Keys)
        {
            if (version.CompareTo(key) < 0)
            {
                if ( lastKey == null ) lastKey = key;
                break;
            }
            lastKey = key;
            if (version.CompareTo(key) == 0) break;
        }

        return Parsers[lastKey];
    }
}
Immersive
  • 1,684
  • 1
  • 11
  • 9