Click here to Skip to main content
15,881,687 members
Articles / Programming Languages / C#

Parsing Command Line Arguments

Rate me:
Please Sign up or sign in to vote.
4.71/5 (25 votes)
26 Apr 2009CPOL2 min read 61.8K   494   83  
The CommandLineParser library provides a simple way to define command line arguments and parse them in your application.
For applications that have one or two arguments, you could probably manage with some switches and ifs, but when there are more arguments, you could use a CommandLineParser library and thus make your code cleaner and more elegant.
using System;
using System.Reflection;
using CommandLineParser.Arguments;
using CommandLineParser.Exceptions;

namespace CommandLineParser.Arguments
{
    /// <summary>
    /// Use BoundedValueArgument for an argument whose value must belong to an interval.
    /// </summary>
    /// <typeparam name="TValue">Type of the value, must support comparison</typeparam>
    /// <include file='Doc\CommandLineParser.xml' path='CommandLineParser/Arguments/BoundedValueArgument/*'/>
    public class BoundedValueArgument<TValue> : CertifiedValueArgument<TValue> 
        where TValue : IComparable
        
    {
        #region min and max values

        private TValue minValue = default(TValue);

        private TValue maxValue = default(TValue);

        private bool useMinValue = false;

        private bool useMaxValue = false; 

        /// <summary>
        /// Minimal allowed value (inclusive)
        /// </summary>
        public TValue MinValue
        {
            get { return minValue; }
            set
            {
                minValue = value;
                UseMinValue = true;
            }
        }

        /// <summary>
        /// Maximal allowed value (inclusive) 
        /// </summary>
        public TValue MaxValue
        {
            get { return maxValue; }
            set
            {
                maxValue = value;
                UseMaxValue = true;
            }
        }

        /// <summary>
        /// When set to true, value is checked for being greater than or equal to <see cref="MinValue"/>
        /// </summary>
        public bool UseMinValue
        {
            get { return useMinValue; }
            set { useMinValue = value; }
        }

        /// <summary>
        /// When set to true, value is checked for being lesser than or equal to <see cref="MaxValue"/>
        /// </summary>
        public bool UseMaxValue
        {
            get { return useMaxValue; }
            set { useMaxValue = value; }
        }

        #endregion

        #region constructor

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>. 
        /// Without any value bounds.
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        public BoundedValueArgument(char shortName)
            : base(shortName)
        {
        }

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>
        /// and <see cref="Argument.LongName">long name</see>. Without any value bounds.
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="longName">Long name of the argument </param>
        public BoundedValueArgument(char shortName, string longName)
            : base(shortName, longName)
        {
        }

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>
        /// and specified maximal value.
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="maxValue">Maximal value of the argument</param>
        public BoundedValueArgument(char shortName, TValue maxValue)
            : base(shortName)
        {
            this.maxValue = maxValue;
            useMaxValue = true; 
        }


        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>
        /// and specified minimal value.
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="minValue">Minimal value of the argument</param>
        public BoundedValueArgument(TValue minValue, char shortName)
            : base(shortName)
        {
            this.minValue = minValue;
            useMinValue = true; 
        }

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>
        /// and specified minimal value and maximal value. 
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="minValue">Minimal value of the argument</param>
        /// <param name="maxValue">Maximal value of the argument</param>
        public BoundedValueArgument(char shortName, TValue minValue, TValue maxValue)
            : base(shortName)
        {
            this.maxValue = maxValue;
            useMaxValue = true; 
            this.minValue = minValue;
            useMinValue = true; 
        }

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>and <see cref="Argument.LongName">long name</see> and specified maximal value.
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="longName">Long name of the argument </param>
        /// <param name="maxValue">Maximal value of the argument</param>
        public BoundedValueArgument(char shortName, string longName, TValue maxValue)
            : base(shortName, longName)
        {
            this.maxValue = maxValue;
            useMaxValue = true; 
        }

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>and <see cref="Argument.LongName">long name</see> and specified minimal value.
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="longName">Long name of the argument </param>
        /// <param name="minValue">minimal value of the argument</param>
        public BoundedValueArgument(TValue minValue, char shortName, string longName)
            : base(shortName, longName)
        {
            this.minValue = minValue;
            useMinValue = true; 
        }


        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>and <see cref="Argument.LongName">long name</see> and specified minimal and maximal value.
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="longName">Long name of the argument </param>
        /// <param name="maxValue">Maximal value of the argument</param>
        /// <param name="minValue">minimal value of the argument</param>
        public BoundedValueArgument(char shortName, string longName, TValue minValue, TValue maxValue)
            : base(shortName, longName)
        {
            this.maxValue = maxValue;
            useMaxValue = true; 
            this.minValue = minValue;
            useMinValue = true; 
        }

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>,
        /// <see cref="Argument.LongName">long name</see> and <see cref="Argument.Description">description</see> and specified maximal value. 
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="longName">Long name of the argument </param>
        /// <param name="description">Description of the argument</param>
        /// <param name="maxValue">Maximal value of the argument</param>
        public BoundedValueArgument(char shortName, string longName, string description, TValue maxValue)
            : base(shortName, longName, description)
        {
            this.maxValue = maxValue;
            useMaxValue = true; 
        }

        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>,
        /// <see cref="Argument.LongName">long name</see> and <see cref="Argument.Description">description</see> and specified minimal value. 
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="longName">Long name of the argument </param>
        /// <param name="description">Description of the argument</param>
        /// <param name="minValue">Minimal value of the argument</param>
        public BoundedValueArgument(TValue minValue, char shortName, string longName, string description)
            : base(shortName, longName, description)
        {
            this.minValue = minValue;
            useMinValue = true; 
        }
        /// <summary>
        /// Creates new value argument with a <see cref="Argument.ShortName">short name</see>,
        /// <see cref="Argument.LongName">long name</see> and <see cref="Argument.Description">description</see> and specified minimal and maximal value. 
        /// </summary>
        /// <param name="shortName">Short name of the argument</param>
        /// <param name="longName">Long name of the argument </param>
        /// <param name="description">Description of the argument</param>
        /// <param name="minValue">Minimal value of the argument</param>
        /// <param name="maxValue">Maximal value of the argument</param>
        public BoundedValueArgument(char shortName, string longName, string description, TValue minValue, TValue maxValue)
            : base(shortName, longName, description)
        {
            this.maxValue = maxValue;
            useMaxValue = true; 
            this.minValue = minValue;
            useMinValue = true; 
        }

        #endregion

        /// <summary>
        /// Checks whether the value belongs to the [<see cref="MinValue"/>, <see cref="MaxValue"/>] interval
        /// (when <see cref="UseMinValue"/> and <see cref="UseMaxValue"/> are set).
        /// </summary>
        /// <param name="value">value to certify</param>
        /// <exception cref="CommandLineArgumentOutOfRangeException">Thrown when <paramref name="value"/> lies outside the interval. </exception>
        internal override void Certify(TValue value)
        {
            if (useMinValue && MinValue.CompareTo(Value) == 1)
            {
                throw new CommandLineArgumentOutOfRangeException(
                    string.Format(Messages.EXC_ARG_BOUNDED_LESSER_THAN_MIN, Value, minValue), Name);
            }

            if (useMaxValue && MaxValue.CompareTo(Value) == -1)
            {
                throw new CommandLineArgumentOutOfRangeException(
                    string.Format(Messages.EXC_ARG_BOUNDED_GREATER_THAN_MAX, Value, maxValue), Name);
            }
        }
    }

    /// <summary>
    /// <para>
    /// Attribute for declaring a class' field a <see cref="BoundedValueArgument{TValue}"/> and 
    /// thus binding a fields value to a certain command line switch argument.
    /// </para>
    /// <para>
    /// Instead of creating an argument explicitly, you can assign a class' field an argument
    /// attribute and let the CommandLineParse take care of binding the attribute to the field.
    /// </para>
    /// </summary>
    /// <remarks>Appliable to fields and properties (public).</remarks>
    /// <remarks>Use <see cref="CommandLineParser.ExtractArgumentAttributes"/> for each object 
    /// you where you have delcared argument attributes.</remarks>
    /// <example>
    /// <code source="Examples\AttributeExample.cs" lang="cs" title="Example of declaring argument attributes" />
    /// </example>
    public class BoundedValueArgumentAttribute : ArgumentAttribute
    {
        private Type argumentType;

        /// <summary>
        /// Creates proper generic <see cref="BoundedValueArgument{TValue}"/> type for <paramref name="type"/>.
        /// </summary>
        /// <param name="type">type of the argument value</param>
        /// <returns>generic type</returns>
        private static Type CreateProperValueArgumentType(Type type)
        {
            Type genericType = typeof(BoundedValueArgument<>);
            Type constructedType = genericType.MakeGenericType(type);
            return constructedType;
        }

        /// <summary>
        /// Creates new instance of BoundedValueArgument. BoundedValueArgument
        /// uses underlaying <see cref="BoundedValueArgument{TValue}"/>.
        /// </summary>
        /// <param name="type">Type of the generic parameter of <see cref="BoundedValueArgument{TValue}"/>.</param>
        /// <param name="shortName"><see cref="Argument.ShortName">short name</see> of the underlying argument</param>
        /// <remarks>
        /// Parameter <paramref name="type"/> has to be either built-in 
        /// type or has to define a static Parse(String, CultureInfo) 
        /// method for reading the value from string.
        /// </remarks>
        public BoundedValueArgumentAttribute(Type type, char shortName)
            : base(CreateProperValueArgumentType(type), shortName)
        {
            argumentType = CreateProperValueArgumentType(type);
        }

        /// <summary>
        /// Creates new instance of BoundedValueArgument. BoundedValueArgument
        /// uses underlaying <see cref="BoundedValueArgument{TValue}"/>.
        /// </summary>
        /// <param name="type">Type of the generic parameter of <see cref="BoundedValueArgument{TValue}"/>.</param>
        /// <param name="shortName"><see cref="Argument.ShortName">short name</see> of the underlying argument</param>
        /// <param name="longName"><see cref="Argument.LongName">long name</see> of the underlying argument</param>
        /// <remarks>
        /// Parameter <paramref name="type"/> has to be either built-in 
        /// type or has to define a static Parse(String, CultureInfo) 
        /// method for reading the value from string.
        /// </remarks>
        public BoundedValueArgumentAttribute(Type type, char shortName, string longName)
            : base(CreateProperValueArgumentType(type), shortName, longName)
        {
            argumentType = CreateProperValueArgumentType(type);
        }     

        /// <summary>
        /// Maximal allowed value (inclusive) 
        /// </summary>
        public object MaxValue
        {
            get
            {
                return argumentType.InvokeMember("MaxValue", BindingFlags.GetProperty, null, Argument, null);
            }
            set
            {
                argumentType.InvokeMember("MaxValue", BindingFlags.SetProperty, null, Argument, new[] { value });
            }
        }
        /// <summary>
        /// Minimal allowed value (inclusive)
        /// </summary>
        public object MinValue
        {
            get
            {
                return argumentType.InvokeMember("MinValue", BindingFlags.GetProperty, null, Argument, null);
            }
            set
            {
                argumentType.InvokeMember("MinValue", BindingFlags.SetProperty, null, Argument, new[]{ value });
            }
        }

        /// <summary>
        /// When set to true, value is checked for being lesser than or equal to <see cref="MaxValue"/>
        /// </summary>
        public bool UseMaxValue
        {
            get
            {
                return (bool)argumentType.InvokeMember("UseMaxValue", BindingFlags.GetProperty, null, Argument, null);
            }
            set
            {
                argumentType.InvokeMember("UseMaxValue", BindingFlags.SetProperty, null, Argument, new object[] { value });
            }
        }

        /// <summary>
        /// When set to true, value is checked for being greater than or equal to <see cref="MinValue"/>
        /// </summary>
        public bool UseMinValue
        {
            get
            {
                return (bool) argumentType.InvokeMember("UseMinValue", BindingFlags.GetProperty, null, Argument, null);
            }
            set
            {
                argumentType.InvokeMember("UseMinValue", BindingFlags.SetProperty, null, Argument, new object[] { value });
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Junior)
Czech Republic Czech Republic
I am a computer science student at Charles University in Prague. I work as a developer of CRM and informational systems.

Comments and Discussions