/// <summary>
        /// Adds an attribute to the name.
        /// </summary>
        /// <param name="sb">The <see cref="StringBuilder"/> containing the name.</param>
        /// <param name="type">The type of the attribute.</param>
        /// <param name="value">The value of the attribute.</param>
        /// <exception cref="ArgumentNullException"><paramref name="sb"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not a valid attribute type.</exception>
        static void AddAttribute(StringBuilder sb, string type, object value)
        {
            if (sb == null)
            {
                throw new ArgumentNullException("sb");
            }

            if (false == RdnSequence.IsValidAttributeType(type))
            {
                throw new ArgumentOutOfRangeException("type", type, "The value is not a valid attribute type.");
            }

            if (sb.Length > 0)
            {
                // Add delimiter
                sb.Append(",");
            }

            sb.Append(type.ToUpper());

            sb.Append('=');

            var escapedValue = RdnSequence.EscapeValue(value);

            sb.Append(escapedValue);
        }
        /// <summary>
        /// Parses a distinguished name represented as a <see cref="String"/>.
        /// </summary>
        /// <param name="value">The value to parse.</param>
        /// <returns>
        /// The resulting <see cref="X501DistinguishedName"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException"><paramref name="value"/> is <c>null</c> or empty.</exception>
        /// <exception cref="FormatException">The value is invalid.</exception>
        public static X501DistinguishedName Parse(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                throw new ArgumentNullException("value");
            }

            var match = RdnSequence.Regex.Match(value);

            if (match == null || match == Match.Empty)
            {
                // No match was found

                throw new FormatException("The value is not a valid distinguished name.");
            }

            var result = new X501DistinguishedName();

            var attributes = match.Groups["attribute"].Captures;

            var values = match.Groups["value"].Captures;

            for (var i = 0; i < attributes.Count; i++)
            {
                var attributeType = attributes[i].Value.ToUpper();

                var attributeValue = values[i].Value;

                var unescapedValue = RdnSequence.UnescapeValue(attributeValue);

                var unescapedValueString = unescapedValue as string;

                if (unescapedValueString == null)
                {
                    // The value is a hexadecimal byte array
                    result.CustomAttributes.Add(new X501DistinguishedNameAttribute(attributeType, unescapedValue));

                    continue;
                }

                switch (attributeType)
                {
                case "CN":
                    result.CommonName = unescapedValueString;
                    break;

                case "O":
                    result.Organization = unescapedValueString;
                    break;

                case "OU":
                    result.OrganizationalUnit = unescapedValueString;
                    break;

                case "L":
                    result.Locality = unescapedValueString;
                    break;

                case "C":
                    result.Country = unescapedValueString;
                    break;

                case "ST":
                    result.StateOrProvince = unescapedValueString;
                    break;

                case "STREET":
                    result.StreetAddress = unescapedValueString;
                    break;

                case "DC":
                    result.DomainComponent = unescapedValueString;
                    break;

                case "UID":
                    result.UserID = unescapedValueString;
                    break;

                case "E":
                    result.Email = unescapedValueString;
                    break;

                case "T":
                    result.Title = unescapedValueString;
                    break;

                case "G":
                    result.GivenName = unescapedValueString;
                    break;

                case "SN":
                    result.Surname = unescapedValueString;
                    break;

                case "I":
                    result.Initial = unescapedValueString;
                    break;

                case "DNQUALIFIER":
                    result.DistinguishedNameQualifier = unescapedValueString;
                    break;

                default:
                    result.CustomAttributes.Add(new X501DistinguishedNameAttribute(attributeType, unescapedValueString));
                    break;
                }
            }

            return(result);
        }