private static ArgumentDefinition CreateArgumentDescriptor( IMutableMemberInfo member, ArgumentBaseAttribute attribute, object defaultValues, ArgumentSetDefinition argSet, object fixedDestination, ArgumentDefinition containingArgument, ServiceConfigurer serviceConfigurer) { if (!member.IsReadable || !member.IsWritable) { var declaringType = member.MemberInfo.DeclaringType; throw new InvalidArgumentSetException(member, string.Format( CultureInfo.CurrentCulture, Strings.MemberNotSupported, member.MemberInfo.Name, declaringType?.Name)); } var defaultFieldValue = (defaultValues != null) ? member.GetValue(defaultValues) : null; return(new ArgumentDefinition(member, attribute, argSet, defaultValue: defaultFieldValue, fixedDestination: fixedDestination, containingArgument: containingArgument, serviceConfigurer: serviceConfigurer)); }
private static ArgumentDefinition CreateArgumentDescriptor( IMutableMemberInfo member, ArgumentBaseAttribute attribute, object defaultValues, ArgumentSetAttribute setAttribute, CommandLineParserOptions options, object fixedDestination) { if (!member.IsReadable || !member.IsWritable) { var declaringType = member.MemberInfo.DeclaringType; throw new InvalidArgumentSetException(member, string.Format( CultureInfo.CurrentCulture, Strings.MemberNotSupported, member.MemberInfo.Name, declaringType?.Name)); } var defaultFieldValue = (defaultValues != null) ? member.GetValue(defaultValues) : null; return(new ArgumentDefinition(member, attribute, setAttribute, options, defaultFieldValue, fixedDestination: fixedDestination)); }
/// <summary> /// Primary constructor. /// </summary> /// <param name="member">Field to describe.</param> /// <param name="attribute">Argument attribute on the field.</param> /// <param name="setAttribute">Attribute on the containing argument set.</param> /// <param name="options">Provides parser options.</param> /// <param name="defaultFieldValue">Default value for the field.</param> /// <param name="parentMember">Parent member under which this field sits.</param> /// <param name="fixedDestination">Optionally provides fixed parse destination object.</param> public ArgumentDefinition(IMutableMemberInfo member, ArgumentBaseAttribute attribute, ArgumentSetAttribute setAttribute, CommandLineParserOptions options, object defaultFieldValue = null, IMutableMemberInfo parentMember = null, object fixedDestination = null) { Debug.Assert(attribute != null); Debug.Assert(member != null); Member = member; ParentMember = parentMember; Attribute = attribute; _setAttribute = setAttribute; FixedDestination = fixedDestination; _isPositional = attribute is PositionalArgumentAttribute; _reporter = options?.Reporter ?? (s => { }); ArgumentType = Attribute.GetArgumentType(member.MemberType); _collectionArgType = AsCollectionType(ArgumentType); HasDefaultValue = attribute.ExplicitDefaultValue || attribute.DynamicDefaultValue; _validationAttributes = GetValidationAttributes(ArgumentType, Member); _argumentParseContext = CreateParseContext(attribute, _setAttribute, options); LongName = GetLongName(attribute, setAttribute, member.MemberInfo); ExplicitShortName = HasExplicitShortName(attribute); ShortName = GetShortName(attribute, setAttribute, member.MemberInfo); DefaultValue = GetDefaultValue(attribute, member, defaultFieldValue); var nullableBase = Nullable.GetUnderlyingType(member.MemberType); if (_collectionArgType != null) { _collectionValues = new ArrayList(); _valueType = _collectionArgType.ElementType; } else if (nullableBase != null) { // For nullable arguments, we use the wrapped type (T in // Nullable<T>) as the value type. Parsing an enum or int is the // same as parsing an enum? or int?, for example, since null can // only arise if the value was not provided at all. _valueType = Attribute.GetArgumentType(nullableBase); } else { _valueType = ArgumentType; } Debug.Assert(_valueType != null); if (Unique && !IsCollection) { throw new InvalidArgumentSetException(member, Strings.UniqueUsedOnNonCollectionArgument); } Debug.Assert(!string.IsNullOrEmpty(LongName)); }
/// <summary> /// Internal constructor. /// </summary> /// <param name="member">Field to describe.</param> /// <param name="attribute">Argument attribute on the field.</param> /// <param name="argSet">Argument set containing this argument.</param> /// <param name="defaultValue">Default value for the field.</param> /// <param name="fixedDestination">Optionally provides fixed parse destination object.</param> /// <param name="containingArgument">Optionally provides a reference /// to the definition of the argument that "contains" these arguments. /// </param> /// <param name="serviceConfigurer">Optionally provides a service configurer.</param> internal ArgumentDefinition(IMutableMemberInfo member, ArgumentBaseAttribute attribute, ArgumentSetDefinition argSet, object defaultValue = null, object fixedDestination = null, ArgumentDefinition containingArgument = null, ServiceConfigurer serviceConfigurer = null) { Member = member ?? throw new ArgumentNullException(nameof(member)); Attribute = attribute ?? throw new ArgumentNullException(nameof(attribute)); ContainingSet = argSet ?? throw new ArgumentNullException(nameof(argSet)); ContainingArgument = containingArgument; FixedDestination = fixedDestination; IsPositional = attribute is PositionalArgumentAttribute; ArgumentType = GetArgumentType(Attribute, member, member.MemberType, serviceConfigurer); CollectionArgumentType = AsCollectionType(ArgumentType); HasDefaultValue = attribute.ExplicitDefaultValue || attribute.DynamicDefaultValue; ValidationAttributes = GetValidationAttributes(ArgumentType, Member); LongName = GetLongName(attribute, argSet.Attribute, member.MemberInfo); ExplicitShortName = HasExplicitShortName(attribute); ShortName = GetShortNameOrNull(attribute, argSet.Attribute, member.MemberInfo); DefaultValue = GetDefaultValue(attribute, member, defaultValue); var nullableBase = Nullable.GetUnderlyingType(member.MemberType); if (CollectionArgumentType != null) { ValueType = CollectionArgumentType.ElementType; } else if (nullableBase != null) { // For nullable arguments, we use the wrapped type (T in // Nullable<T>) as the value type. Parsing an enum or int is the // same as parsing an enum? or int?, for example, since null can // only arise if the value was not provided at all. ValueType = GetArgumentType(Attribute, member, nullableBase, serviceConfigurer); } else { ValueType = ArgumentType; } Debug.Assert(ValueType != null); if (Unique && !IsCollection) { throw new InvalidArgumentSetException(member, Strings.UniqueUsedOnNonCollectionArgument); } Debug.Assert(!string.IsNullOrEmpty(LongName)); }
private static object GetDefaultValue(ArgumentBaseAttribute attribute, IMutableMemberInfo member, object defaultFieldValue) { object value; if (attribute.DynamicDefaultValue) { value = defaultFieldValue; } else if (attribute.ExplicitDefaultValue) { value = attribute.DefaultValue; } else { try { // N.B. This will fail if it's a reflection-only type. value = member.MemberType.GetDefaultValue(); } catch (InvalidOperationException) { value = null; } } // Validate the value's type. if (value != null && !member.MemberType.GetTypeInfo().IsAssignableFrom(value.GetType())) { // See if it's implicitly convertible. if (!member.MemberType.IsImplicitlyConvertibleFrom(value)) { throw new InvalidArgumentSetException(member, string.Format( CultureInfo.CurrentCulture, Strings.DefaultValueIsOfWrongType, member.MemberInfo.Name, value.GetType().Name, member.MemberType.Name)); } } return(value); }
/// <summary> /// Retrieves the <see cref="IArgumentType"/> type for the provided type. /// </summary> /// <param name="attrib">The argument attribute to use.</param> /// <param name="memberInfo">Member info for the argument.</param> /// <param name="type">The type to look up.</param> /// <param name="configurer">Optionally provides service configurer.</param> /// <returns>The found type.</returns> private static IArgumentType GetArgumentType(ArgumentBaseAttribute attrib, IMutableMemberInfo memberInfo, Type type, ServiceConfigurer configurer) { // First try to retrieve the default IArgumentType implementation // for this type, but don't fail if we can't find one. Types.ArgumentType.TryGetType(type, out IArgumentType argType); // If we don't have any overrides, then we already have the // implementation we'll need (or it doesn't exist). if (attrib.ArgumentType == null && attrib.Parser == null && attrib.Formatter == null && attrib.Completer == null) { if (argType == null) { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.TypeNotSupported, type.Name)); } return(argType); } var serviceCollection = new ServiceCollection(); configurer?.Invoke(serviceCollection); serviceCollection.AddSingleton <Type>(type); serviceCollection.AddSingleton <IMutableMemberInfo>(memberInfo); if (attrib.Parser != null) { serviceCollection.AddTransient(typeof(IStringParser), attrib.Parser); } if (attrib.Formatter != null) { serviceCollection.AddTransient(typeof(IObjectFormatter), attrib.Formatter); } if (attrib.Completer != null) { serviceCollection.AddTransient(typeof(IStringCompleter), attrib.Completer); } if (attrib.ArgumentType != null) { if (argType != null) { serviceCollection.AddSingleton <IArgumentType>(argType); } serviceCollection.AddTransient(typeof(object), attrib.ArgumentType); argType = (IArgumentType)serviceCollection .BuildServiceProvider() .GetService <object>(); } if (argType == null) { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Strings.TypeNotSupported, type.Name)); } serviceCollection.AddSingleton <IArgumentType>(argType); if (attrib.Parser == null && attrib.Formatter == null && attrib.Completer == null) { return(argType); } var provider = serviceCollection.BuildServiceProvider(); var parser = provider.GetService <IStringParser>(); var formatter = provider.GetService <IObjectFormatter>(); var completer = provider.GetService <IStringCompleter>(); return(new ArgumentTypeExtension(argType, parser, formatter, completer)); }
private static IReadOnlyList <ArgumentValidationAttribute> GetValidationAttributes(IArgumentType argType, IMutableMemberInfo memberInfo) { var member = memberInfo.MemberInfo; var collectionArgType = AsCollectionType(argType); var argTypeToCheck = (collectionArgType != null) ? collectionArgType.ElementType : argType; var attributes = member.GetAttributes <ArgumentValidationAttribute>().ToList(); foreach (var attrib in attributes.Where(attrib => !attrib.AcceptsType(argTypeToCheck))) { throw new InvalidArgumentSetException(memberInfo, string.Format( CultureInfo.CurrentCulture, Strings.BadValidationAttribute, attrib.GetType().Name, argType.Type.Name)); } return(attributes); }
/// <summary> /// Constructor that takes member info. /// </summary> /// <param name="memberInfo">Info about the problematic member.</param> /// <param name="message">The message string.</param> /// <param name="innerException">The inner exception.</param> internal InvalidArgumentSetException(IMutableMemberInfo memberInfo, string message = null, Exception innerException = null) : this(memberInfo.MemberInfo.DeclaringType, message, innerException) { MemberInfo = memberInfo; }
private static IEnumerable <ArgumentDefinition> CreateArgumentDescriptorsIfApplicable(IMutableMemberInfo member, object defaultValues, ArgumentSetDefinition argSet, object fixedDestination, ArgumentDefinition containingArgument, ServiceConfigurer serviceConfigurer) { var descriptors = Enumerable.Empty <ArgumentDefinition>(); var argAttrib = member.MemberInfo.GetSingleAttribute <ArgumentBaseAttribute>(); if (argAttrib != null) { descriptors = descriptors.Concat( new[] { CreateArgumentDescriptor( member, argAttrib, defaultValues, argSet, fixedDestination, containingArgument, serviceConfigurer) }); } return(descriptors); }
private static IEnumerable <ArgumentDefinition> CreateArgumentDescriptorsIfApplicable(IMutableMemberInfo member, object defaultValues, ArgumentSetAttribute setAttribute, CommandLineParserOptions options, object fixedDestination) { var descriptors = Enumerable.Empty <ArgumentDefinition>(); var argAttrib = member.MemberInfo.GetSingleAttribute <ArgumentBaseAttribute>(); if (argAttrib != null) { descriptors = descriptors.Concat(new[] { CreateArgumentDescriptor(member, argAttrib, defaultValues, setAttribute, options, fixedDestination) }); } var groupAttrib = member.MemberInfo.GetSingleAttribute <ArgumentGroupAttribute>(); if (groupAttrib != null) { // TODO: investigate defaultValues descriptors = descriptors.Concat(GetArgumentDescriptors(member.MemberType, setAttribute, /*defaultValues=*/ null, options, fixedDestination)); } return(descriptors); }