private static TOptions InternalParse <TOptions>(string[] args, int offsetInArray, ArgumentGroupInfo arguments, ParserOptions parseOptions)
            where TOptions : new()
        {
            TOptions options = new TOptions();
            int      currentLogicalPosition = 0;

            // let's match them to actual required args, in positional
            if (arguments.RequiredArguments.Count > 0)
            {
                ParseRequiredParameters(args, offsetInArray, arguments, options, ref currentLogicalPosition);
            }

            // we are going to keep track of any properties that have not been specified so that we can set their default value.
            var unmatchedOptionalProperties = ParseOptionalParameters(args, offsetInArray, arguments, options, ref currentLogicalPosition);

            // for all the remaining optional properties, set their default value.
            foreach (var property in unmatchedOptionalProperties)
            {
                //get the default value..
                var    value        = property.GetCustomAttribute <OptionalArgumentAttribute>();
                object defaultValue = value.DefaultValue;

                // If we want to read values from the environment, try to get the value
                if (parseOptions.ReadFromEnvironment && !value.IsCollection && parseOptions.VariableNamePrefix != null)
                {
                    var envVar = Environment.GetEnvironmentVariable($"{parseOptions.VariableNamePrefix}{value.Name}");

                    if (!string.IsNullOrEmpty(envVar))
                    {
                        defaultValue = PropertyHelpers.GetValueForProperty(envVar, property);
                    }
                }

                property.SetValue(options, Convert.ChangeType(defaultValue, property.PropertyType));
            }

            return(options);
        }