Skip to main content

Simple parameter fetching from a console args array. An auxiliary class (InputArguments), which parses arguments and fills a dictionary with key-value pairs. The dictionary allows accessing a parameter value in the way like this: InputArguments["-url"] or InputArguments["url"].

using System;
using System.Collections.Generic;

namespace Utils
{
    /// <summary>
    /// A simple command line input argument parser.
    /// </summary>
    /// <remarks>
    /// Based on:
    /// http://dotnetfollower.com/wordpress/2012/03/c-simple-command-line-arguments-parser/
    /// </remarks>
    /// <example>
    ///     program.exe -url "http://dotnetfollower.com" -useElevatedPrivileges
    ///
    ///     static void Main(string[] args)
    ///     {
    ///         InputArguments arguments = new InputArguments(args);
    ///
    ///         Console.WriteLine(arguments["-url"]);
    ///         if (arguments.Contains("useElevatedPrivileges"))
    ///         {
    ///             Console.WriteLine("useElevatedPrivileges is set");
    ///         }
    ///     }
    ///
    ///     // The above mentioned command line arguments will be turned into the
    ///     // following key-value pairs:
    ///
    ///     {["-url", "http://dotnetfollower.com"]}
    ///     {["-useElevatedPrivileges", null]}
    /// </example>
    public class InputArguments
    {
        public const string DEFAULT_KEY_LEADING_PATTERN = "-";

        private readonly string _keyLeadingPattern;

        public string KeyLeadingPattern
        {
            get
            {
                return _keyLeadingPattern;
            }
        }

        protected Dictionary<string, string> ParsedArguments { get; set; }

        public InputArguments(string[] args, string keyLeadingPattern)
        {
            ParsedArguments = new Dictionary<string, string>(
                StringComparer.OrdinalIgnoreCase);

            _keyLeadingPattern = !string.IsNullOrEmpty(keyLeadingPattern)
                ? keyLeadingPattern : DEFAULT_KEY_LEADING_PATTERN;

            if (args != null &&
                args.Length > 0)
            {
                Parse(args);
            }
        }

        public InputArguments(string[] args) : this(args, null)
        {
        }

        public string this [string key]
        {
            get
            {
                return GetValue(key);
            }
            set
            {
                if (key != null)
                {
                    ParsedArguments[key] = value;
                }
            }
        }

        public bool Contains(string key)
        {
            string adjustedKey;

            return ContainsKey(key, out adjustedKey);
        }

        public virtual string GetPeeledKey(string key)
        {
            return IsKey(key) ? key.Substring(
                _keyLeadingPattern.Length) : key;
        }

        public virtual string GetDecoratedKey(string key)
        {
            return !IsKey(key) ? string.Format("{0}{1}",
                _keyLeadingPattern, key) : key;
        }

        public virtual bool IsKey(string str)
        {
            return str.StartsWith(_keyLeadingPattern);
        }

        protected void Parse(string[] args)
        {
            for (int i = 0; i < args.Length; i ++)
            {
                if (args[i] == null)
                {
                    continue;
                }

                string key = null;
                string val = null;

                if (IsKey(args[i]))
                {
                    key = args[i];

                    if (i + 1 < args.Length &&
                        !IsKey(args[i + 1]))
                    {
                        val = args[i + 1];
                        i ++;
                    }
                }
                else
                {
                    val = args[i];
                }

                // adjustment
                if (key == null)
                {
                    key = val;
                    val = null;
                }

                if (key != null)
                {
                    ParsedArguments[key] = val;
                }
            }
        }

        protected virtual string GetValue(string key)
        {
            string adjustedKey;

            return ContainsKey(key, out adjustedKey)
                ? ParsedArguments[adjustedKey] : null;
        }

        /// <summary>
        /// Check the existance of a specified argument.
        /// </summary>
        /// <example>
        ///     bool exists = GetBoolValue("-useElevatedPrivileges");
        ///     if (exists) { ... do someething }
        /// </example>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public bool GetBoolValue(string key)
        {
            string adjustedKey;
            if (ContainsKey(key, out adjustedKey))
            {
                bool res;
                bool.TryParse(ParsedArguments[adjustedKey], out res);

                return res;
            }

            return false;
        }

        protected virtual bool ContainsKey(string key, out string adjustedKey)
        {
            adjustedKey = key;
            if (ParsedArguments.ContainsKey(key))
            {
                return true;
            }

            if (IsKey(key))
            {
                string peeledKey = GetPeeledKey(key);
                if (ParsedArguments.ContainsKey(peeledKey))
                {
                    adjustedKey = peeledKey;

                    return true;
                }

                return false;
            }

            string decoratedKey = GetDecoratedKey(key);
            if (ParsedArguments.ContainsKey(decoratedKey))
            {
                adjustedKey = decoratedKey;

                return true;
            }

            return false;
        }
    }
}

// ----------------------------------------------------------------------------
// Updated Version
// ----------------------------------------------------------------------------

public abstract class InputArguments
{
    private const string DefaultKeyLeadingPattern = "-";

    protected string KeyLeadingPattern { get; }

    protected Dictionary<string, string> ParsedArguments { get; }

    protected InputArguments(IReadOnlyList<string> arguments, string keyLeadingPattern = null)
    {
        ParsedArguments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        KeyLeadingPattern = !string.IsNullOrEmpty(keyLeadingPattern)
            ? keyLeadingPattern : DefaultKeyLeadingPattern;

        if (arguments != null && arguments.Count > 0)
            Parse(arguments);
    }

    public string this[string key]
    {
        get => GetValue(key);
        set
        {
            if (key != null) ParsedArguments[key] = value;
        }
    }

    public bool Contains(string key)
    {
        return ContainsKey(key, out _);
    }

    private string GetPeeledKey(string key)
    {
        return IsKey(key) ? key.Substring(
            KeyLeadingPattern.Length) : key;
    }

    private string GetDecoratedKey(string key)
    {
        return !IsKey(key) ? $"{KeyLeadingPattern}{key}" : key;
    }

    private bool IsKey(string str)
    {
        return str.StartsWith(KeyLeadingPattern, StringComparison.Ordinal);
    }

    private void Parse(IReadOnlyList<string> arguments)
    {
        for (var i = 0; i < arguments.Count; i++)
        {
            if (arguments[i] == null)
            {
                continue;
            }

            string key = null;
            string val = null;

            if (IsKey(arguments[i]))
            {
                key = arguments[i];
                if (i + 1 < arguments.Count && !IsKey(arguments[i + 1]))
                {
                    val = arguments[i + 1];
                    i++;
                }
            }
            else
            {
                val = arguments[i];
            }

            // adjustment
            if (key == null)
            {
                key = val;
                val = null;
            }

            if (key != null)
            {
                ParsedArguments[key] = val;
            }
        }
    }

    protected string GetValue(string key)
    {
        return ContainsKey(key, out var adjustedKey)
            ? ParsedArguments[adjustedKey].Trim()
            : null;
    }

    public bool ContainsKey(string key, out string adjustedKey)
    {
        adjustedKey = key;
        if (ParsedArguments.ContainsKey(key))
            return true;

        if (IsKey(key))
        {
            var peeledKey = GetPeeledKey(key);
            if (ParsedArguments.ContainsKey(peeledKey))
            {
                adjustedKey = peeledKey;
                return true;
            }
            return false;
        }

        var decoratedKey = GetDecoratedKey(key);
        if (ParsedArguments.ContainsKey(decoratedKey))
        {
            adjustedKey = decoratedKey;
            return true;
        }

        return false;
    }
}