File: System\Xml\Linq\XName.cs
Web Access
Project: src\src\libraries\System.Private.Xml.Linq\src\System.Private.Xml.Linq.csproj (System.Private.Xml.Linq)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics.CodeAnalysis;
using System.Runtime.Serialization;
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
 
namespace System.Xml.Linq
{
    /// <summary>
    /// Represents a name of an XML element or attribute. This class cannot be inherited.
    /// </summary>
    public sealed class XName : IEquatable<XName>, ISerializable
    {
        private readonly XNamespace _ns;
        private readonly string _localName;
        private readonly int _hashCode;
 
        /// <summary>
        /// Constructor, internal so that external users must go through the Get() method to create an XName.
        /// </summary>
        internal XName(XNamespace ns, string localName)
        {
            _ns = ns;
            _localName = XmlConvert.VerifyNCName(localName);
            _hashCode = ns.GetHashCode() ^ localName.GetHashCode();
        }
 
        /// <summary>
        /// Gets the local (unqualified) part of the name.
        /// </summary>
        /// <seealso cref="XName.Namespace"/>
        public string LocalName
        {
            get { return _localName; }
        }
 
        /// <summary>
        /// Gets the namespace of the name.
        /// </summary>
        public XNamespace Namespace
        {
            get { return _ns; }
        }
 
        /// <summary>
        /// Gets the namespace name part of the name.
        /// </summary>
        public string NamespaceName
        {
            get { return _ns.NamespaceName; }
        }
 
        /// <summary>
        /// Returns the expanded XML name in the format: {namespaceName}localName.
        /// </summary>
        public override string ToString()
        {
            if (_ns.NamespaceName.Length == 0) return _localName;
            return "{" + _ns.NamespaceName + "}" + _localName;
        }
 
        /// <summary>
        /// Returns an <see cref="XName"/> object created from the specified expanded name.
        /// </summary>
        /// <param name="expandedName">
        /// A string containing an expanded XML name in the format: {namespace}localname.
        /// </param>
        /// <returns>
        /// An <see cref="XName"/> object constructed from the specified expanded name.
        /// </returns>
        public static XName Get(string expandedName)
        {
            ArgumentException.ThrowIfNullOrEmpty(expandedName);
            if (expandedName[0] == '{')
            {
                int i = expandedName.LastIndexOf('}');
                if (i <= 1 || i == expandedName.Length - 1) throw new ArgumentException(SR.Format(SR.Argument_InvalidExpandedName, expandedName));
                return XNamespace.Get(expandedName, 1, i - 1).GetName(expandedName, i + 1, expandedName.Length - i - 1);
            }
            else
            {
                return XNamespace.None.GetName(expandedName);
            }
        }
 
        /// <summary>
        /// Returns an <see cref="XName"/> object from a local name and a namespace.
        /// </summary>
        /// <param name="localName">A local (unqualified) name.</param>
        /// <param name="namespaceName">An XML namespace.</param>
        /// <returns>An XName object created from the specified local name and namespace.</returns>
        public static XName Get(string localName, string namespaceName)
        {
            return XNamespace.Get(namespaceName).GetName(localName);
        }
 
        /// <summary>
        /// Converts a string formatted as an expanded XML name ({namespace}localname) to an XName object.
        /// </summary>
        /// <param name="expandedName">A string containing an expanded XML name in the format: {namespace}localname.</param>
        /// <returns>An XName object constructed from the expanded name.</returns>
        [CLSCompliant(false)]
        [return: NotNullIfNotNull(nameof(expandedName))]
        public static implicit operator XName?(string? expandedName)
        {
            return expandedName != null ? Get(expandedName) : null;
        }
 
        /// <summary>
        /// Determines whether the specified <see cref="XName"/> is equal to the current <see cref="XName"/>.
        /// </summary>
        /// <param name="obj">The XName to compare to the current XName.</param>
        /// <returns>
        /// true if the specified <see cref="XName"/> is equal to the current XName; otherwise false.
        /// </returns>
        /// <remarks>
        /// For two <see cref="XName"/> objects to be equal, they must have the same expanded name.
        /// </remarks>
        public override bool Equals([NotNullWhen(true)] object? obj)
        {
            return (object)this == obj;
        }
 
        /// <summary>
        /// Serves as a hash function for <see cref="XName"/>. GetHashCode is suitable
        /// for use in hashing algorithms and data structures like a hash table.
        /// </summary>
        public override int GetHashCode()
        {
            return _hashCode;
        }
 
        // The overloads of == and != are included to enable comparisons between
        // XName and string (e.g. element.Name == "foo"). C#'s predefined reference
        // equality operators require one operand to be convertible to the type of
        // the other through reference conversions only and do not consider the
        // implicit conversion from string to XName.
 
        /// <summary>
        /// Returns a value indicating whether two instances of <see cref="XName"/> are equal.
        /// </summary>
        /// <param name="left">The first XName to compare.</param>
        /// <param name="right">The second XName to compare.</param>
        /// <returns>true if left and right are equal; otherwise false.</returns>
        /// <remarks>
        /// This overload is included to enable the comparison between
        /// an instance of XName and string.
        /// </remarks>
        public static bool operator ==(XName? left, XName? right)
        {
            return (object?)left == (object?)right;
        }
 
        /// <summary>
        /// Returns a value indicating whether two instances of <see cref="XName"/> are not equal.
        /// </summary>
        /// <param name="left">The first XName to compare.</param>
        /// <param name="right">The second XName to compare.</param>
        /// <returns>true if left and right are not equal; otherwise false.</returns>
        /// <remarks>
        /// This overload is included to enable the comparison between
        /// an instance of XName and string.
        /// </remarks>
        public static bool operator !=(XName? left, XName? right)
        {
            return (object?)left != (object?)right;
        }
 
        /// <summary>
        /// Indicates whether the current <see cref="XName"/> is equal to
        /// the specified <see cref="XName"/>
        /// </summary>
        /// <param name="other">The <see cref="XName"/> to compare with the
        /// current <see cref="XName"/></param>
        /// <returns>
        /// Returns true if the current <see cref="XName"/> is equal to
        /// the specified <see cref="XName"/>. Returns false otherwise.
        /// </returns>
        bool IEquatable<XName>.Equals(XName? other)
        {
            return (object)this == (object?)other;
        }
 
        /// <summary>
        /// Populates a <see cref="SerializationInfo"/> with the data needed to
        /// serialize the <see cref="XName"/>
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> to populate with data</param>
        /// <param name="context">The destination for this serialization</param>
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            throw new PlatformNotSupportedException();
        }
    }
}