/// <summary> /// /// </summary> /// <param name="options">Object decorated by Plossum's attributes.</param> public CommandLineParser(object options) { if (options == null) { throw new ArgumentNullException("options"); } Options = options; CommandLineManagerAttribute = PlossumAttributesHelper.GetCommandLineManagerAttribute(options.GetType()); OptionAttributes = PlossumAttributesHelper.GetCommandLineOptionAttributes(options.GetType()); GroupAttributesDic = PlossumAttributesHelper.GetCommandLineOptionGroupAttributesDic(options.GetType()); }
public static string AnalyzeAssignedOptions(object optionsAssigned) { if (optionsAssigned == null) { throw new ArgumentNullException("optionsAssigned"); } var typeOfParametersAndOptions = optionsAssigned.GetType(); var propertiesOfParametersAndOptions = new List <PropertyInfo>(typeOfParametersAndOptions.GetProperties()); var managerAttribute = PlossumAttributesHelper.GetCommandLineManagerAttribute(typeOfParametersAndOptions); var isCaseSensitive = managerAttribute.IsCaseSensitive; var allOptionAttributes = PlossumAttributesHelper.GetCommandLineOptionAttributes(typeOfParametersAndOptions); var allPropertyInfo = PlossumAttributesHelper.GetOptionProperties(typeOfParametersAndOptions); List <PropertyInfo> propertyInfoOfAssignedProperties = new List <PropertyInfo>(); List <CommandLineOptionAttribute> optionAttributesOfAssignedProperties = new List <CommandLineOptionAttribute>(); foreach (PropertyInfo propertyInfo in propertiesOfParametersAndOptions) { var propertyValue = propertyInfo.GetValue(optionsAssigned, null); if (propertyValue == null) { continue; } int parameterOrder = PropertyHelper.GetParameterOrder(propertyInfo); if (parameterOrder < int.MaxValue)//so this is a fixed parameter { continue; } else//option { var defaultValue = PropertyHelper.ReadDefaultValue(propertyInfo); var optionAttribute = PlossumAttributesHelper.GetCommandLineOptionAttribute(propertyInfo); if (!propertyValue.Equals(defaultValue)) { optionAttributesOfAssignedProperties.Add(optionAttribute); propertyInfoOfAssignedProperties.Add(propertyInfo); } } } #region about Grouped options var optionAttributesGrouped = optionAttributesOfAssignedProperties.GroupBy(d => d.GroupId).OrderBy(k => k.Key); var allGroupAttributesDic = PlossumAttributesHelper.GetCommandLineOptionGroupAttributesDic(typeOfParametersAndOptions); StringBuilder builder = new StringBuilder(); foreach (var item in allGroupAttributesDic) { var groupId = item.Key; var groupAttribute = item.Value; var optionAttributes = optionAttributesGrouped.FirstOrDefault(d => d.Key == groupId); switch (groupAttribute.Require) { case OptionGroupRequirement.None: continue; case OptionGroupRequirement.AtMostOne: if (optionAttributes == null) { continue; } if (!(optionAttributes.Count() <= 1)) { builder.AppendLine(String.Format("Group {0} requires at most one option defined, but actually these are {1} options defined", groupAttribute.Name, optionAttributes.Count())); } break; case OptionGroupRequirement.AtLeastOne: if ((optionAttributes == null) || !(optionAttributes.Count() >= 1)) { builder.AppendLine(String.Format("Group {0} requires at least one option defined, but actually these is none defined", groupAttribute.Name)); } break; case OptionGroupRequirement.ExactlyOne: if (optionAttributes == null) { builder.AppendLine(String.Format("Group {0} requires exactly one option defined, but actually these is none defined", groupAttribute.Name)); } else if (!(optionAttributes.Count() == 1)) { builder.AppendLine(String.Format("Group {0} requires exactly one option defined, but actually these are {1} options defined.", groupAttribute.Name, optionAttributes.Count())); } break; case OptionGroupRequirement.All: if (optionAttributes == null) { builder.AppendLine(String.Format("Group {0} requires all options defined, but actually these is none defined", groupAttribute.Name)); } else { var numberOfOptionsOfGroup = allOptionAttributes.Count(d => d.GroupId == groupId); var delta = numberOfOptionsOfGroup - optionAttributes.Count(); if (delta != 0) { builder.AppendLine(String.Format("Group {0} requires all options defined, but actually there are {1} options(s) missing.", groupAttribute.Name, delta)); } } break; default: break; } } #endregion #region about Prohibits for (int i = 0; i < propertyInfoOfAssignedProperties.Count; i++) { var optionAttribute = optionAttributesOfAssignedProperties[i]; if (String.IsNullOrEmpty(optionAttribute.Prohibits)) { continue; } var propertyInfo = propertyInfoOfAssignedProperties[i]; string[] optionNamesProhibited = optionAttribute.Prohibits.Split(mSeparators, StringSplitOptions.RemoveEmptyEntries); if (optionNamesProhibited.Length == 0) { continue; } for (int k = 0; k < propertyInfoOfAssignedProperties.Count; k++) { var nextPropertyInfo = propertyInfoOfAssignedProperties[k]; bool matched = false; if (optionNamesProhibited.Contains(nextPropertyInfo.Name, isCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase)) { matched = true; } else { var nextOptionAttribute = optionAttributesOfAssignedProperties[k]; if (optionNamesProhibited.Contains(nextOptionAttribute.Name, isCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase)) { matched = true; } else { if ((nextOptionAttribute.AliasesArray != null) && (nextOptionAttribute.AliasesArray.Length > 0)) { matched = optionNamesProhibited.Any(d => nextOptionAttribute.AliasesArray.Contains(d, isCaseSensitive ? StringComparer.CurrentCulture : StringComparer.CurrentCultureIgnoreCase)); } } } if (matched) { builder.AppendLine(String.Format("Option {0} defined is prohibited since option {1} is already defined.", nextPropertyInfo.Name, propertyInfo.Name)); } } } #endregion for (int i = 0; i < propertyInfoOfAssignedProperties.Count; i++) { var optionAttribute = optionAttributesOfAssignedProperties[i]; var propertyInfo = propertyInfoOfAssignedProperties[i]; if (propertyInfo.PropertyType.IsArray) { var array = propertyInfo.GetValue(optionsAssigned, null); var list = array as Array; var arrayLength = list.Length; if ((optionAttribute.MaxOccurs > 1) && (arrayLength > optionAttribute.MaxOccurs)) { builder.AppendLine(String.Format("Option {0} with MaxOccurs={1} has {2} presented.", propertyInfo.Name, optionAttribute.MaxOccurs, arrayLength)); } if ((optionAttribute.MinOccurs > 0) && (arrayLength < optionAttribute.MinOccurs)) { builder.AppendLine(String.Format("Option {0} with MinOccurs={1} has {2} presented.", propertyInfo.Name, optionAttribute.MinOccurs, arrayLength)); } if ((optionAttribute.MaxOccurs > 0) && (optionAttribute.MinOccurs > optionAttribute.MaxOccurs)) { builder.AppendLine(String.Format("In option {0} MinOccurs={1} is greater than MaxOccurs={2} .", propertyInfo.Name, optionAttribute.MinOccurs, optionAttribute.MaxOccurs)); } } } for (int i = 0; i < allPropertyInfo.Length; i++) { var optionAttribute = allOptionAttributes[i]; var propertyInfo = allPropertyInfo[i]; if (propertyInfo.PropertyType.IsArray) { var array = propertyInfo.GetValue(optionsAssigned, null); var list = array as Array; // var arrayLength = list.Length; if ((list == null) && (optionAttribute.MinOccurs > 0)) { builder.AppendLine(String.Format("Option {0} with MinOccurs={1} has no value.", propertyInfo.Name, optionAttribute.MinOccurs)); } } else { if (optionAttribute.MaxOccurs > 1) { builder.AppendLine(String.Format("Option {0} must not have MaxOccurs greater than 1.", propertyInfo.Name)); } } } #region about MaxValue and MinValue for (int i = 0; i < propertyInfoOfAssignedProperties.Count; i++) { var optionAttribute = optionAttributesOfAssignedProperties[i]; var propertyInfo = propertyInfoOfAssignedProperties[i]; var maxValue = optionAttribute.MaxValue; var minValue = optionAttribute.MinValue; if ((maxValue == null) && (minValue == null)) { continue; } if (propertyInfo.PropertyType.IsArray) { var array = propertyInfo.GetValue(optionsAssigned, null); var list = array as Array; if (list == null) { continue; } var firstMember = list.GetValue(0); var memberType = firstMember.GetType(); if (!IsNumericType(memberType)) { builder.AppendLine(String.Format("Options {0} is not of numeric type, and must not have either MaxValue or MinValue defined in CommandLineOptionAttribute.", propertyInfo.Name)); continue; } if (maxValue != null) { if (memberType.Equals(decimalType) && !decimalType.Equals(maxValue)) { maxValue = Convert.ToDecimal(maxValue); } foreach (var m in list) { IComparable comparable = m as IComparable; if (comparable.CompareTo(maxValue) > 0) { builder.AppendLine(String.Format("In option {0}, this member {1} is greater than maxValue {2}.", propertyInfo.Name, m, maxValue)); } } } if (minValue != null) { if (memberType.Equals(decimalType) && !decimalType.Equals(minValue)) { minValue = Convert.ToDecimal(minValue); } foreach (var m in list) { IComparable comparable = m as IComparable; if (comparable.CompareTo(minValue) < 0) { builder.AppendLine(String.Format("In option {0}, this member {1} is less than than minValue {2}.", propertyInfo.Name, m, minValue)); } } } } else { if (!IsNumericType(propertyInfo.PropertyType)) { builder.AppendLine(String.Format("Options {0} is not of numeric type, and must not have either MaxValue or MinValue defined in CommandLineOptionAttribute.", propertyInfo.Name)); continue; } if (maxValue != null) { var m = propertyInfo.GetValue(optionsAssigned, null); IComparable comparable = m as IComparable; if (propertyInfo.PropertyType.Equals(decimalType) && !decimalType.Equals(maxValue)) { maxValue = Convert.ToDecimal(maxValue); } if (comparable.CompareTo(maxValue) > 0) { builder.AppendLine(String.Format("In option {0}, this member {1} is greater than maxValue {2}.", propertyInfo.Name, m, maxValue)); } } if (minValue != null) { var m = propertyInfo.GetValue(optionsAssigned, null); IComparable comparable = m as IComparable; if (propertyInfo.PropertyType.Equals(decimalType) && !decimalType.Equals(minValue)) { minValue = Convert.ToDecimal(minValue); } if (comparable.CompareTo(minValue) < 0) { builder.AppendLine(String.Format("In option {0}, this member {1} is less than than minValue {2}.", propertyInfo.Name, m, minValue)); } } } } #endregion return(builder.ToString()); }