/// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="defaultLength">Default length for generated values.
        /// This is only used when <see cref="GetRandomString"/> has an input length
        /// of 0.</param>
        /// <param name="characterSet">The character set to base the random generation off of.
        /// You MAY have duplicate chars, which is useful to increase the frequency of those characters.</param>
        /// <param name="symbolsToAdd">We've made this a separate parameter, because in most users
        /// cases, they want the default ascii alpha-numeric chars (A-Z, a-z, 0-9), but usually
        /// would want their own customized set of which symbols to use. This way, you don't have to
        /// send in a custom char set every time just to set which symbols you want to set. Note:
        /// if this is set, <paramref name="addDefaultSymbolSet"/> CANNOT be set to true.</param>
        /// <param name="addDefaultSymbolSet">True to add the default symbol set (see static
        /// property: <see cref="SymbolCharsDef"/>, which is not readonly, so you may set your own
        /// default for this globally if desired). Do NOT set this to true if you send in your own
        /// <paramref name="symbolsToAdd"/>.</param>
        /// <param name="enforceDistinctCharSet">This will filter the input char set with a Distinct
        /// operation, which will (without error) remove any (presumably accidental) duplicates.
        /// This is NOT run by default, because you may *want* to increase a chars probability by
        /// repeating it n number of times in the input char set.</param>
        /// <param name="bufferLength">Sets the buffer size in bytes of the internal <see cref="CryptoRandom"/>
        /// instance. Increase this value to a kilobyte or greater in order to get extremely good performance.
        /// This makes most sense when reusing this instance more than once.</param>
        public RandomStringGenerator(
            int defaultLength           = 0,
            string characterSet         = null,
            string symbolsToAdd         = null,
            bool addDefaultSymbolSet    = false,
            bool enforceDistinctCharSet = false,
            int bufferLength            = 512)
        {
            if (defaultLength > 0)
            {
                DefaultLength = defaultLength.Max(0);
            }

            CharacterSet = characterSet ?? CharSetDef;

            if (addDefaultSymbolSet)
            {
                if (symbolsToAdd.NotNulle())
                {
                    throw new ArgumentException($"Argument '{nameof(addDefaultSymbolSet)}' cannot be true while '{nameof(symbolsToAdd)}' is set (not null).");
                }
                symbolsToAdd = SymbolCharsDef;
            }

            if (symbolsToAdd.NotNulle())
            {
                CharacterSet += symbolsToAdd;
            }

            // need this HashSet because its hard to detect if a char is actually a symbol later
            // (char.IsSymbol is deficient, so just counting as 'symbol' any non letterOrDigit
            char[] symbols = CharacterSet.Where(c => !char.IsLetterOrDigit(c)).ToArray();
            if (symbols.NotNulle())
            {
                SymbolsHashset = new HashSet <char>(symbols.Distinct());
                SymbolSet      = new string(symbols);
            }

            _charSet = enforceDistinctCharSet
                                ? CharacterSet.Distinct().ToArray()
                                : CharacterSet.ToArray();

            if (_charSet.IsNulle())
            {
                throw new ArgumentOutOfRangeException("No characters were set.", nameof(CharacterSet));
            }

            bufferLength = (CharacterSet.Length * 2).Max(bufferLength);    // gets bigger of two, doesn't let input be smaller than charSet*2
            bufferLength = bufferLength.MinMax(256, 1024 * 4);             // 4 kb max, 1/2 a byte min, for this max, no need to generate huge buffer value, perf is regardless once your getting > 4 kb

            _cryptoRandom = new CryptoRandom(bufferLength);

            // If true, before generating the random string, we will radomize the source char set
            // as well, making for a doubly randomized result. TRUE by default.
            bool randomizeCharSet = true;

            if (randomizeCharSet)
            {
                _charSet = _cryptoRandom.RandomShuffle(_charSet);

                bool viewDiagnostic = false;
                if (viewDiagnostic)
                {
                    //// just to see none of the original chars were lost in that sort:
                    string shuffledStr = new string(_charSet);
                    string sortedStr   = _charSet.OrderBy(c => c).JoinToString("");                   // view to witness no chars were dropped (or added)
                }
            }
        }