/// <summary>
        /// Attempts to construct and return a file-based properties provider
        /// </summary>
        /// <param name="defaultPropertiesFileDirectory">Directory in which to look for the default properties file (optional)</param>
        /// <param name="commandLineArguments">List of command line arguments (optional)</param>
        /// <returns>False if errors occurred when constructing the provider, otherwise true</returns>
        /// <remarks>If a properties file could not be located then an empty provider will be returned</remarks>
        public static bool TryCreateProvider(IEnumerable <ArgumentInstance> commandLineArguments, string defaultPropertiesFileDirectory, ILogger logger, out IAnalysisPropertyProvider provider)
        {
            if (commandLineArguments == null)
            {
                throw new ArgumentNullException("commandLineArguments");
            }
            if (string.IsNullOrWhiteSpace(defaultPropertiesFileDirectory))
            {
                throw new ArgumentNullException("defaultDirectory");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }

            // If the path to a properties file was specified on the command line, use that.
            // Otherwise, look for a default properties file in the default directory.
            bool settingsFileArgExists = ArgumentInstance.TryGetArgumentValue(DescriptorId, commandLineArguments, out string propertiesFilePath);

            if (ResolveFilePath(propertiesFilePath, defaultPropertiesFileDirectory, logger, out AnalysisProperties locatedPropertiesFile))
            {
                if (locatedPropertiesFile == null)
                {
                    provider = EmptyPropertyProvider.Instance;
                }
                else
                {
                    provider = new FilePropertyProvider(locatedPropertiesFile, !settingsFileArgExists);
                }
                return(true);
            }

            provider = null;
            return(false);
        }
        /// <summary>
        /// Parses the supplied arguments. Logs errors for unrecognized, duplicate or missing arguments.
        /// </summary>
        /// <param name="argumentInstances">A list of argument instances that have been recognized</param>
        public bool ParseArguments(string[] commandLineArgs, ILogger logger, out IEnumerable <ArgumentInstance> argumentInstances)
        {
            if (commandLineArgs == null)
            {
                throw new ArgumentNullException("commandLineArgs");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }


            bool parsedOk = true;

            // List of values that have been recognized
            IList <ArgumentInstance> recognized = new List <ArgumentInstance>();

            foreach (string arg in commandLineArgs)
            {
                string             prefix;
                ArgumentDescriptor descriptor;

                if (TryGetMatchingDescriptor(arg, out descriptor, out prefix))
                {
                    string newId = descriptor.Id;

                    if (!descriptor.AllowMultiple && IdExists(newId, recognized))
                    {
                        string existingValue;
                        ArgumentInstance.TryGetArgumentValue(newId, recognized, out existingValue);
                        logger.LogError(Resources.ERROR_CmdLine_DuplicateArg, arg, existingValue);
                        parsedOk = false;
                    }
                    else
                    {
                        // Store the argument
                        string argValue = arg.Substring(prefix.Length);
                        recognized.Add(new ArgumentInstance(descriptor, argValue));
                    }
                }
                else
                {
                    if (!this.allowUnrecognized)
                    {
                        logger.LogError(Resources.ERROR_CmdLine_UnrecognizedArg, arg);
                        parsedOk = false;
                    }

                    Debug.WriteLineIf(this.allowUnrecognized, "Ignoring unrecognized argument: " + arg);
                }
            }

            // We'll check for missing arguments this even if the parsing failed so we output as much detail
            // as possible about the failures.
            parsedOk &= CheckRequiredArgumentsSupplied(recognized, logger);

            argumentInstances = parsedOk ? recognized : Enumerable.Empty <ArgumentInstance>();

            return(parsedOk);
        }
        /// <summary>
        /// Parses the supplied arguments. Logs errors for unrecognized, duplicate or missing arguments.
        /// </summary>
        /// <param name="argumentInstances">A list of argument instances that have been recognized</param>
        public bool ParseArguments(string[] commandLineArgs, ILogger logger, out IEnumerable <ArgumentInstance> argumentInstances)
        {
            if (commandLineArgs == null)
            {
                throw new ArgumentNullException("commandLineArgs");
            }
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }

            var parsedOk = true;

            // List of values that have been recognized
            IList <ArgumentInstance> recognized = new List <ArgumentInstance>();

            foreach (var arg in commandLineArgs)
            {
                if (TryGetMatchingDescriptor(arg, out ArgumentDescriptor descriptor, out string prefix))
                {
                    var newId = descriptor.Id;

                    if (!descriptor.AllowMultiple && IdExists(newId, recognized))
                    {
                        ArgumentInstance.TryGetArgumentValue(newId, recognized, out string existingValue);
                        logger.LogError(Resources.ERROR_CmdLine_DuplicateArg, arg, existingValue);
                        parsedOk = false;
                    }
                    else
                    {
                        // Store the argument
                        var argValue = arg.Substring(prefix.Length);
                        recognized.Add(new ArgumentInstance(descriptor, argValue));
                    }
                }