/// <summary> /// Adds the supplied <see cref="AttributeField"/> to the <see cref="ArgumentDictionary"/>. /// </summary> /// <param name="attr">The <see cref="ArgumentAttribute"/> to use the <see cref="ArgumentAttribute.LongName"/> or <see cref="AttributeField.Attr.ShortName"/> of.</param> /// <param name="fields">The <see cref="AttributeField"/> to add to the <see cref="ArgumentDictionary"/>.</param> public void Add(ArgumentAttribute attr, AttributeField field) { if (this.innerContainer.ContainsKey(attr.LongName)) { this.innerContainer[attr.LongName].Add(field); } else { this.innerContainer.Add(attr.LongName, new List <AttributeField> { field }); } if (this.innerContainer.ContainsKey(attr.ShortName)) { this.innerContainer[attr.ShortName].Add(field); } else { this.innerContainer.Add(attr.ShortName, new List <AttributeField> { field }); } this.cachedValues = null; }
/// <summary> /// For the specified <see cref="AttributeField"/> <paramref name="field"/>, for all instances in the <paramref name="instanceSource"/>, set the associated field to the supplied <paramref name="value"/>. /// </summary> /// <param name="value">The value to use for the <paramref name="field"/>'s new value.</param> /// <param name="field">The <see cref="AttributeField"/> to target - instances in <paramref name="instanceSource"/> will have their value changed for this field.</param> /// <param name="instanceSource">The instances upon which to change the associated fields values.</param> private static void SetInstanceFieldValue( string value, AttributeField field, IEnumerable <object> instanceSource) { foreach (object instance in instanceSource.Where(x => x.GetType().GetFields(Context.bindingFlags).Contains(field.Field))) { field.Field.SetValue(instance, Convert.ChangeType(value, field.Field.FieldType)); } }
/// <summary> /// Invokes the <see cref="Context"/>, initializing any objects in <see cref="Context.Instances"/> with the appropriate values. /// </summary> /// <param name="mode">Controls the scope of the invocation. View <see cref="ControlModes"/> for information on what these do.</param> public static void Invoke(ControlModes mode = ControlModes.RegisteredTypesOnly) { if (Context.Invoked) { throw new InvalidOperationException("Cannot invoke multiple times."); } if (mode == ControlModes.RegisteredTypesOnly) { Context.fields = new Lazy <ArgumentDictionary>(() => Context.Iterate( Context.Instances .Select(x => x.GetType()) .Distinct())); } IEnumerable <string> alreadyUsedNames = Context.manualArguments .Where(x => fields.Value.ContainsKey(x.LongName)) .Select(x => x.LongName) .Concat( Context.manualArguments .Where(x => fields.Value.ContainsKey(x.ShortName)) .Select(x => x.ShortName)); if (alreadyUsedNames.Any()) { throw new InvalidOperationException( $"ArgumentGroup contained argument names already in use: {string.Join(", ", alreadyUsedNames)}"); } Context.SetInstanceFieldValues(Context.Fields, Context.Instances); List <IArgument> userSupplied = Context.manualArguments.Invoke(Context.ParsedArgs).ToList(); foreach (TreeNode <string> argument in Context.ParsedArgs.Root.Children.Where(x => !userSupplied.Any(y => x.Value == y.LongName || x.Value == y.ShortName))) { if (fields.Value.ContainsKey(argument.Value)) { IEnumerable <AttributeField> currentPosition = fields.Value[argument.Value]; if (currentPosition.Count() == 1 && // There is a single expected field for that attribute. currentPosition.First().Attr.Position == -1 && // The only expected field is a flag. argument.Children.Count == 0) // No value was supplied for the field. { Context.SetInstanceFieldValue( "True", currentPosition.First(), Context.Instances); userSupplied.Add(currentPosition.First().Attr); } else if (currentPosition.Count() == argument.Children.Count) { for (int counter = 0; counter < argument.Children.Count; counter++) { AttributeField currentField = currentPosition.ElementAt(counter); Context.SetInstanceFieldValue( argument.Children[counter].Value, currentField, Context.Instances); userSupplied.Add(currentField.Attr); } } else { throw new ArgumentException($"Malformed argument \"{argument.Value}\"."); } } else { throw new ArgumentException($"Unrecognized argument \"{argument.Value}\"."); } } IArgument[] remainingArguments = Context.Fields .Select(x => (IArgument)x.Attr) .Concat(Context.manualArguments) .Except(userSupplied) .ToArray(); if (remainingArguments.Any(x => x.Required)) { IEnumerable <string> missingRequiredArguments = remainingArguments .Where(x => x.Required) .Select(x => $"{x.ShortName} ({x.LongName})"); throw new ArgumentException( $"Missing required arguments: {string.Join(", ", missingRequiredArguments)}"); } Context.Invoked = true; }