/// <summary>
        /// Parses the given value into a <see cref="TypeName"/>.
        /// </summary>
        /// <param name="value">The value to parse.</param>
        /// <returns>The parsed <see cref="TypeName"/>.</returns>
        public static TypeName Parse(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                throw new ArgumentNullException("value", "value must contain a value.");
            }

            string[] parts = (from p in value.Split(',')
                              let t = p.Trim()
                              where !string.IsNullOrEmpty(t)
                              select t).ToArray();

            if (parts.Length >= 2)
            {
                string[] nameParts = parts[0].Split('.');

                if (nameParts.Length >= 2)
                {
                    string ns = string.Join(".", nameParts.Take(nameParts.Length - 1).ToArray());
                    string name = nameParts[nameParts.Length - 1];

                    TypeName typeName = new TypeName()
                    {
                        Assembly = parts[1],
                        Name = name,
                        Namespace = ns
                    };

                    foreach (string part in parts.Skip(2))
                    {
                        bool valid = true;
                        string[] keyValue = (from p in part.Split('=')
                                             let t = p.Trim()
                                             where !string.IsNullOrEmpty(t)
                                             select t).ToArray();

                        if (keyValue.Length == 2)
                        {
                            switch (keyValue[0].ToUpperInvariant())
                            {
                                case "VERSION":
                                    typeName.Version = new Version(keyValue[1]);
                                    break;
                                case "CULTURE":
                                    typeName.Culture = keyValue[1];
                                    break;
                                case "PUBLICKEYTOKEN":
                                    typeName.PublicKeyToken = keyValue[1];
                                    break;
                                default:
                                    valid = false;
                                    break;
                            }
                        }
                        else
                        {
                            valid = false;
                        }

                        if (!valid)
                        {
                            throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Unknown type name token: '{0}'.", part));
                        }
                    }

                    return typeName;
                }
                else
                {
                    throw new FormatException("The specified value does not contain a namespace and a type name.");
                }
            }
            else
            {
                throw new FormatException("The specified value is not in a valid format for a type name.");
            }
        }
        /// <summary>
        /// Clones this instance into a new <see cref="TypeName"/> instance.
        /// </summary>
        /// <returns>A cloned <see cref="TypeName"/> instance.</returns>
        public TypeName Clone()
        {
            TypeName clone = new TypeName();
            clone.assembly = this.assembly;
            clone.culture = this.culture;
            clone.name = this.name;
            clone.ns = this.ns;
            clone.publicKeyToken = this.publicKeyToken;

            if (this.Version != null)
            {
                clone.Version = new Version(this.Version.ToString());
            }

            return clone;
        }
        /// <summary>
        /// Merges the metadata type information from the given <see cref="ITaskItem"/>
        /// with the given <see cref="TypeName"/>, returning a new <see cref="TypeName"/> result instance.
        /// </summary>
        /// <param name="typeName">The <see cref="TypeName"/> to merge metadata with.</param>
        /// <param name="taskItem">The <see cref="ITaskItem"/> to get type metadata from.</param>
        /// <returns>A new, merged, <see cref="TypeName"/> instance.</returns>
        private static TypeName MergeWithMetadata(TypeName typeName, ITaskItem taskItem)
        {
            TypeName result = typeName.Clone();
            string value = (taskItem.GetMetadata("Assembly") ?? string.Empty).Trim();

            if (!string.IsNullOrEmpty(value))
            {
                result.Assembly = value;
            }

            if (MetadataNameDefined(taskItem, "RemoveAssembly"))
            {
                result.Assembly = null;
            }

            value = (taskItem.GetMetadata("Culture") ?? string.Empty).Trim();

            if (!string.IsNullOrEmpty(value))
            {
                result.Culture = value;
            }

            if (MetadataNameDefined(taskItem, "RemoveCulture"))
            {
                result.Culture = null;
            }

            value = (taskItem.GetMetadata("Name") ?? string.Empty).Trim();

            if (!string.IsNullOrEmpty(value))
            {
                result.Name = value;
            }

            if (MetadataNameDefined(taskItem, "RemoveName"))
            {
                result.Name = null;
            }

            value = (taskItem.GetMetadata("Namespace") ?? string.Empty).Trim();

            if (!string.IsNullOrEmpty(value))
            {
                result.Namespace = value;
            }

            if (MetadataNameDefined(taskItem, "RemoveNamespace"))
            {
                result.Namespace = null;
            }

            value = (taskItem.GetMetadata("PublicKeyToken") ?? string.Empty).Trim();

            if (!string.IsNullOrEmpty(value))
            {
                result.PublicKeyToken = value;
            }

            if (MetadataNameDefined(taskItem, "RemovePublicKeyToken"))
            {
                result.PublicKeyToken = null;
            }

            value = (taskItem.GetMetadata("Version") ?? string.Empty).Trim();

            if (!string.IsNullOrEmpty(value))
            {
                result.Version = new Version(value);
            }

            if (MetadataNameDefined(taskItem, "RemoveVersion"))
            {
                result.Version = null;
            }

            return result;
        }