Example #1
0
        /// <summary>
        /// Iterates through a collection of key/value pairs, where the key is a property name of
        /// the object to populate and the value is the value to set the property to.
        /// </summary>
        /// <param name="arguments">Collection of key/value pairs using a /key=value syntax.</param>
        /// <param name="valueToPopulate">The object to set properties for.</param>
        /// <returns>true if parsing is successful; otherwise, false.</returns>
        public static bool ParseArguments(IEnumerable <string> arguments, Object valueToPopulate)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(valueToPopulate);

            CommandLineDictionary commandLineDictionary = new CommandLineDictionary(arguments);

            foreach (string key in commandLineDictionary.Keys)
            {
                PropertyDescriptor property = properties[key];
                if (property == null)
                {
                    return(false);
                }

                TypeConverter typeConverter = TypeDescriptor.GetConverter(property.PropertyType);
                if (typeConverter == null)
                {
                    return(false);
                }

                object convertedValue = typeConverter.ConvertFromInvariantString(commandLineDictionary[key]);
                properties[key].SetValue(valueToPopulate, convertedValue);
            }

            return(true);
        }
        /// <summary>
        /// Creates a dictionary that is populated with key/value pairs from a command line
        /// that supports syntax where options are provided in the form "/key=value".
        /// This method supports the ability to specify delimiter characters for options in
        /// the command line.
        /// </summary>
        /// <param name="arguments">Key/value pairs.</param>
        /// <param name="keyCharacter">A character that precedes a key.</param>
        /// <param name="valueCharacter">A character that separates a key from a value.</param>
        /// <returns></returns>
        public static CommandLineDictionary FromArguments(IEnumerable <string> arguments, char keyCharacter, char valueCharacter)
        {
            CommandLineDictionary cld = new CommandLineDictionary();

            cld.KeyCharacter   = keyCharacter;
            cld.ValueCharacter = valueCharacter;
            foreach (string argument in arguments)
            {
                cld.AddArgument(argument);
            }

            return(cld);
        }
        /// <summary>
        /// Creates a string that represents key/value arguments for the properties of the
        /// specified object. For example, an object with a name (string) of "example" and a
        /// priority value (integer) of 1 translates to '/name=example  /priority=1'. This
        /// can be used to send data structures through the command line.
        /// </summary>
        /// <param name="valueToConvert">Value to create key/value arguments from.</param>
        /// <returns>Space-delimited key/value arguments.</returns>
        public static string ToString(object valueToConvert)
        {
            IEnumerable <PropertyDescriptor> properties         = TypeDescriptor.GetProperties(valueToConvert).Cast <PropertyDescriptor>();
            IEnumerable <PropertyDescriptor> propertiesOnParent = TypeDescriptor.GetProperties(valueToConvert.GetType().BaseType).Cast <PropertyDescriptor>();

            properties = properties.Except(propertiesOnParent);
            CommandLineDictionary commandLineDictionary = new CommandLineDictionary();

            foreach (PropertyDescriptor property in properties)
            {
                commandLineDictionary[property.Name] = property.GetValue(valueToConvert).ToString();
            }

            return(commandLineDictionary.ToString());
        }
        /// <summary>
        /// Sets properties on an object from a series of key/value string
        /// arguments that are in the form "/PropertyName=Value", where the
        /// value is converted from a string into the property type.
        /// </summary>
        /// <param name="valueToPopulate">The object to set properties on.</param>
        /// <param name="args">The key/value arguments describing the property names and values to set.</param>
        /// <returns>
        /// Indicates whether the properties were successfully set.  Reasons for failure reasons include
        /// a property name that does not exist or a value that cannot be converted from a string.
        /// </returns>
        /// <exception cref="System.ArgumentException">Thrown when one of the key/value strings cannot be parsed into a property.</exception>
        public static void ParseArguments(this object valueToPopulate, IEnumerable <string> args)
        {
            CommandLineDictionary commandLineDictionary = CommandLineDictionary.FromArguments(args);

            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(valueToPopulate);

            // Ensure required properties are specified.
            foreach (PropertyDescriptor property in properties)
            {
                // See whether any of the attributes on the property is a RequiredAttribute.
                if (property.Attributes.Cast <Attribute>().Any(attribute => attribute is RequiredAttribute))
                {
                    // If so, and the command line dictionary doesn't contain a key matching
                    // the property's name, it means that a required property isn't specified.
                    if (!commandLineDictionary.ContainsKey(property.Name))
                    {
                        throw new ArgumentException("A value for the " + property.Name + " property is required.");
                    }
                }
            }

            foreach (KeyValuePair <string, string> keyValuePair in commandLineDictionary)
            {
                PropertyDescriptor property = properties[keyValuePair.Key];
                if (property == null)
                {
                    throw new ArgumentException("A matching property of name " + keyValuePair.Key + " on type " + valueToPopulate.GetType() + " could not be found.");
                }

                // If the value is null/empty and the property is a bool, we
                // treat it as a flag, which means its presence means true.
                if (String.IsNullOrEmpty(keyValuePair.Value) &&
                    (property.PropertyType == typeof(bool) || property.PropertyType == typeof(bool?)))
                {
                    property.SetValue(valueToPopulate, true);
                    continue;
                }

                object valueToSet;

                // We support a limited set of collection types. Setting a List<T>
                // is one of the most flexible types as it supports three different
                // interfaces, but the catch is that we don't support the concrete
                // Collection<T> type. We can expand it to support Collection<T>
                // in the future, but the code will get a bit uglier.
                switch (property.PropertyType.Name)
                {
                case "IEnumerable`1":
                case "ICollection`1":
                case "IList`1":
                case "List`1":
                    MethodInfo methodInfo        = typeof(CommandLineParser).GetMethod("FromCommaSeparatedList", BindingFlags.Static | BindingFlags.NonPublic);
                    Type[]     genericArguments  = property.PropertyType.GetGenericArguments();
                    MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);
                    valueToSet = genericMethodInfo.Invoke(null, new object[] { keyValuePair.Value });
                    break;

                default:
                    TypeConverter typeConverter = TypeDescriptor.GetConverter(property.PropertyType);
                    if (typeConverter == null || !typeConverter.CanConvertFrom(typeof(string)))
                    {
                        throw new ArgumentException("Unable to convert from a string to a property of type " + property.PropertyType + ".");
                    }
                    valueToSet = typeConverter.ConvertFromInvariantString(keyValuePair.Value);
                    break;
                }

                properties[keyValuePair.Key].SetValue(valueToPopulate, valueToSet);
            }

            return;
        }