/// <summary>
 /// Constructs a new relative reference.
 /// </summary>
 /// <param name="userInfo">The user information portion of the authority, if any. This may be <c>null</c> to indicate no user info, or the empty string to indicate empty user info.</param>
 /// <param name="host">The host name portion of the authority, if any. This is converted to lowercase. This may be <c>null</c> to indicate no host name, or the empty string to indicate an empty host name.</param>
 /// <param name="port">The port portion of the authority, if any. This may be <c>null</c> to indicate no port, or the empty string to indicate an empty port. This must be <c>null</c>, the empty string, or a valid port as defined by <see cref="Util.IsValidPort"/>.</param>
 /// <param name="pathSegments">The path segments. Dot segments are normalized. May not be <c>null</c>, neither may any element be <c>null</c>.</param>
 /// <param name="query">The query. This may be <c>null</c> to indicate no query, or the empty string to indicate an empty query.</param>
 /// <param name="fragment">The fragment. This may be <c>null</c> to indicate no fragment, or the empty string to indicate an empty fragment.</param>
 public RelativeReference(string userInfo, string host, string port, IEnumerable <string> pathSegments, string query, string fragment)
 {
     _userInfo     = userInfo;
     _host         = new NormalizedHost(host);
     _port         = new NormalizedPort(port);
     _pathSegments = new NormalizedPathSegments(NormalizePath(_userInfo, _host.Value, _port.Value, pathSegments), _userInfo, _host.Value, _port.Value, dotNormalize: false);
     Query         = query;
     Fragment      = fragment;
 }
        /// <summary>
        /// Constructs a new URI instance.
        /// </summary>
        /// <param name="scheme">The scheme. This is converted to lowercase. Must be a valid scheme as defined by <see cref="Utility.IsValidScheme"/>.</param>
        /// <param name="userInfo">The user information portion of the authority, if any. This may be <c>null</c> to indicate no user info, or the empty string to indicate empty user info.</param>
        /// <param name="host">The host name portion of the authority, if any. This is converted to lowercase. This may be <c>null</c> to indicate no host name, or the empty string to indicate an empty host name.</param>
        /// <param name="port">The port portion of the authority, if any. This may be <c>null</c> to indicate no port, or the empty string to indicate an empty port. This must be <c>null</c>, the empty string, or a valid port as defined by <see cref="Utility.IsValidPort"/>.</param>
        /// <param name="pathSegments">The path segments. Dot segments are normalized. May not be <c>null</c>, neither may any element be <c>null</c>.</param>
        /// <param name="query">The query. This may be <c>null</c> to indicate no query, or the empty string to indicate an empty query.</param>
        /// <param name="fragment">The fragment. This may be <c>null</c> to indicate no fragment, or the empty string to indicate an empty fragment.</param>
        public GenericUniformResourceIdentifier(string scheme, string?userInfo, string?host, string?port, IEnumerable <string> pathSegments, string?query, string?fragment)
        {
            _ = scheme ?? throw new ArgumentNullException(nameof(scheme));
            if (!Utility.IsValidScheme(scheme))
            {
                throw new ArgumentException("Invalid scheme " + scheme, nameof(scheme));
            }
            Scheme        = scheme.ToLowerInvariant();
            UserInfo      = userInfo;
            _host         = new NormalizedHost(host);
            _port         = new NormalizedPort(port);
            _pathSegments = new NormalizedPathSegments(pathSegments, UserInfo, _host.Value, _port.Value);
            Query         = query;
            Fragment      = fragment;

            _factory = CreateFactory(scheme);
        }