public static object GetValueFromArgsArray(string[] args, int offsetInArray, ref int currentLogicalPosition, PropertyInfo targetType) { ActualArgumentAttribute value = targetType.GetCustomAttribute <ActualArgumentAttribute>(); object argValue = null; if (!value.IsCollection) { argValue = GetValueForProperty(args[offsetInArray + currentLogicalPosition], targetType); currentLogicalPosition++; } else { // we are going to support just string lists. int indexLastEntry = args.Length; for (int i = offsetInArray + currentLogicalPosition; i < args.Length; i++) { if (args[i][0] == '-') { // stop at the first additional argument indexLastEntry = i; break; } } // create the list string[] list = new string[indexLastEntry - currentLogicalPosition - offsetInArray]; Array.Copy(args, offsetInArray + currentLogicalPosition, list, 0, indexLastEntry - currentLogicalPosition - offsetInArray); argValue = new List <string>(list); currentLogicalPosition = indexLastEntry; } return(Convert.ChangeType(argValue, targetType.PropertyType)); }
public static void ScanTypeForProperties <TOptions>(out TypeArgumentInfo tInfo) { tInfo = new TypeArgumentInfo(); PropertyInfo[] propertiesOnType = typeof(TOptions).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public); // first of all, find the commandArgument, if any. tInfo.ActionArgument = FindCommandProperty(propertiesOnType); // we want to be able to support empty groups. if (tInfo.ActionArgument != null && IsEnum(tInfo.ActionArgument.PropertyType)) { // get the values of the enum. var enumValues = Enum.GetValues(tInfo.ActionArgument.PropertyType); // Sort the enum by the enum values Array.Sort(enumValues); // add them to the dictionary now to make sure we preserve the order foreach (var val in enumValues) { if (!tInfo.ArgumentGroups.ContainsKey(val.ToString())) { tInfo.ArgumentGroups.Add(val.ToString(), new ArgumentGroupInfo()); } } } // parse the rest of the properties foreach (var property in propertiesOnType) { // get the group containing this property (note: more than one group can have the same property) // this allows common required parameters var groupsWhereThePropertyIsParticipating = GetGroupsForProperty(tInfo, property); var actualAttribs = property.GetCustomAttributes <ActualArgumentAttribute>().ToList(); if (actualAttribs.Count > 1) { throw new ArgumentException($"Only one of Required/Optional attribute are allowed per property ({property.Name}). [Red!Help information might be incorrect!]"); } // if we have no attributes on that property, move on ActualArgumentAttribute baseAttrib = actualAttribs.FirstOrDefault(); if (baseAttrib == null) { continue; } // add the property to add the groups it is a part of if (baseAttrib is RequiredArgumentAttribute) { foreach (ArgumentGroupInfo grpPropInfo in groupsWhereThePropertyIsParticipating) { // do we have an override for this property? If we do, use that, otherwise use the regular one. if (!grpPropInfo.OverridePositions.TryGetValue(property, out int requiredPositionIndex)) { requiredPositionIndex = (int)baseAttrib.GetArgumentId(); } if (grpPropInfo.RequiredArguments.ContainsKey(requiredPositionIndex)) { throw new ArgumentException("Two required arguments share the same position!!"); } grpPropInfo.RequiredArguments[requiredPositionIndex] = property; } } else if (baseAttrib is OptionalArgumentAttribute) { foreach (ArgumentGroupInfo grpPropInfo in groupsWhereThePropertyIsParticipating) { if (grpPropInfo.OptionalArguments.ContainsKey((string)baseAttrib.GetArgumentId())) { throw new ArgumentException("Two optional arguments share the same name!!"); } grpPropInfo.OptionalArguments[(string)baseAttrib.GetArgumentId()] = property; } } } ArgumentGroupInfo grp; // remove the empty one, if empty if (tInfo.ArgumentGroups.TryGetValue(string.Empty, out grp)) { if (grp.OptionalArguments.Count == 0 && grp.RequiredArguments.Count == 0) { tInfo.ArgumentGroups.Remove(string.Empty); } } }