예제 #1
0
        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));
        }
예제 #2
0
        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));
        }
예제 #3
0
        /// <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));
        }
예제 #4
0
        /// <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));
        }
예제 #5
0
        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);
        }
예제 #6
0
        /// <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));
        }
예제 #7
0
        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;
 }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }