/*       Copyright (c) Eric Ledoux.  All rights reserved.       */
/* See http://www.dwell.net/terms for code sharing information. */

// Topic.cs
//
// Implements class Topic and related types.
//

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.UI;
using System.Xml;
using DwellNet.CodeDoc;
using CodeDocApi.Properties;

namespace DwellNet.CodeDoc
{

Topic Class

A documentation topic.

[DebuggerDisplay("{DebuggerDisplay}")]
public class Topic : IComparable<Topic>
{
    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
Topic.s_nonFileNameCharRegex Field

Matches a character that we don't want to include in a file name returned by e.g. MakeValidFileName.

    static readonly Regex s_nonFileNameCharRegex =
        new Regex(@"[^a-zA-Z0-9_~\[\],.]");

    
Topic.s_insignificantWhiteSpaceRegex Field

Matches what would be considered insignificant white space in HTML.

    static readonly Regex s_insignificantWhiteSpaceRegex =
        new Regex(@"[ \r\n\t]+");

    
Topic.m_docSet Field

Holds the value of the DocumentationSet property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    DocumentationSet m_docSet;

    
Topic.m_name Field

Holds the value of the Name property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_name;

    
Topic.m_id Field

Holds the value of the Id property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    int m_id;

    
Topic.m_topicKind Field

Holds the value of the TopicKind property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TopicKind m_topicKind;

    
Topic.m_parentTopic Field

Holds the value of the ParentTopic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Topic m_parentTopic;

    
Topic.m_sourceFile Field

Holds the value of the SourceFile property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    SourceFile m_sourceFile;

    
Topic.m_xmlCommentToken Field

Holds the value of the FirstXmlComment property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    XmlCommentToken m_xmlCommentToken;

    
Topic.m_xml Field

Holds the value of the Xml property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_xml;

    
Topic.m_startOfDeclaration Field

Holds the value of the StartOfDeclaration property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Token m_startOfDeclaration;

    
Topic.m_modifiers Field

Holds the value of the Modifiers property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList m_modifiers;

    
Topic.m_namespaceName Field

Holds the value of the NamespaceName property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList m_namespaceName;

    
Topic.m_namespaceTopic Field

Holds the value of the NamespaceTopic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    NamespaceTopic m_namespaceTopic;

    
Topic.m_memberType Field

Holds the value of the MemberType property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList m_memberType;

    
Topic.m_explicitPrefix Field

Holds the value of the ExplicitPrefix property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList m_explicitPrefix;

    
Topic.m_memberName Field

Holds the value of the MemberName property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_memberName;

    
Topic.m_typeParameters Field

Holds the value of the TypeParameters property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList[] m_typeParameters;

    
Topic.m_baseTypes Field

Holds the value of the BaseTypes property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList[] m_baseTypes;

    
Topic.m_baseClassTopic Field

Holds the value of the BaseClassTopic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Topic m_baseClassTopic;

    
Topic.m_constraints Field

Holds the value of the Constraints property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList m_constraints;

    
Topic.m_parameters Field

Holds the value of the Parameters property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    List<Parameter> m_parameters;

    
Topic.m_methodKind Field

Holds the value of the MethodKind property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    MethodKind m_methodKind;

    
Topic.m_propertyKind Field

Holds the value of the PropertyKind property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    PropertyKind m_propertyKind;

    
Topic.m_enumValueNames Field

Holds the value of the EnumValueNames property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    List<string> m_enumValueNames;

    
Topic.m_attributes Field

Holds the value of the Attributes property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    List<TokenList> m_attributes;

    
Topic.m_getAccessor Field

Holds the value of the GetAccessor property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Accessor m_getAccessor;

    
Topic.m_setAccessor Field

Holds the value of the SetAccessor property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Accessor m_setAccessor;

    
Topic.m_usingContext Field

Holds the value of the UsingContext property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    UsingContext m_usingContext;

    
Topic.m_childTopics Field

Holds the value of the ChildTopics property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    List<Topic> m_childTopics;

    
Topic.m_isTypeTopic Field

Holds the value of the IsTypeTopic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    bool m_isTypeTopic;

    
Topic.m_isDocumented Field

Holds the value of the IsDocumented property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    bool m_isDocumented;

    
Topic.m_overloadListTopic Field

Holds the value of the OverloadListTopic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    OverloadListTopic m_overloadListTopic;

    
Topic.m_xmlSectionsHtml Field

Holds the HTML for each top-level section (e.g. "<summary>" or "<param>" of the value of the XML documentation associated with this topic. Element n corresponds to the XmlCommentSectionKind enumeration value equal to n; the value is a list since there can be multiple sections of the same kind (e.g. one "<param>" section per parameter).

    List<XmlCommentSection>[] m_xmlSectionsHtml;

    //////////////////////////////////////////////////////////////////////////
    // Private Properties
    //

#if DEBUG
    /// <summary>
    /// Gets a string displayed in the debugger.
    /// </summary>
    public string DebuggerDisplay
    {
        get
        {
            TokenList nameList = QualifiedMemberName;
            if (nameList == null)
                return TopicKind.ToString();
            string name = nameList.ToString();
            if (name == null)
                return TopicKind.ToString();
            else
            {
                string moreInfo;
                if (TopicKind == TopicKind.MethodTopic)
                {
                    if (MethodKind != MethodKind.Normal)
                        moreInfo = String.Format(" ({0})", MethodKind);
                    else
                        moreInfo = "";
                }
                else
                if (TopicKind == TopicKind.PropertyTopic)
                {
                    if (PropertyKind != PropertyKind.Normal)
                        moreInfo = String.Format(" ({0})", PropertyKind);
                    else
                        moreInfo = "";
                }
                else
                    moreInfo = "";
                return String.Format("{0} {1}{2}", TopicKind,
                    QualifiedMemberName, moreInfo);
            }
        }
    }
#endif

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
Topic.DocumentationSet Property

The documentation set that contains this topic.

    public DocumentationSet DocumentationSet
    {
        [DebuggerStepThrough]
        get
        {
            return m_docSet;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_docSet = value;
        }
    }

    
Topic.TopicKind Property

Gets the TopicKind value indicating what kind of topic this is.

    public TopicKind TopicKind
    {
        [DebuggerStepThrough]
        get
        {
            return m_topicKind;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_topicKind = value;
        }
    }

    
Topic.ParentTopic Property

The topic of the type specified by ParentTypeName. null if none or not applicable. Note that TopicKind.NamespaceTopic topics have no parent topic.

    public Topic ParentTopic
    {
        [DebuggerStepThrough]
        get
        {
            return m_parentTopic;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_parentTopic = value;
        }
    }

    
Topic.SourceFile Property

The source file containing this topic; null if none.

    public SourceFile SourceFile
    {
        [DebuggerStepThrough]
        get
        {
            return m_sourceFile;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_sourceFile = value;
        }
    }

    
Topic.FirstXmlComment Property

The XML comment associated with this topic; null if none.

    public XmlCommentToken FirstXmlComment
    {
        [DebuggerStepThrough]
        get
        {
            return m_xmlCommentToken;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_xmlCommentToken = value;
                // do nothing if there is no array of 
        }
    }

    
Topic.Xml Property

The XML markup from XML comment token(s) starting at FirstXmlComment; null if none.

    public string Xml
    {
        [DebuggerStepThrough]
        get
        {
            return m_xml;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_xml = value;
        }
    }

    
Topic.StartOfDeclaration Property

The beginning of the declaration following the XML comment(s) associated with this topic; null if none.

    public Token StartOfDeclaration
    {
        [DebuggerStepThrough]
        get
        {
            return m_startOfDeclaration;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_startOfDeclaration = value;
                // do nothing if there is no array of 
        }
    }

    
Topic.Modifiers Property

The modifiers of the member documented by this topic, if applicable; for example, "public static". null if none or not applicable.

    public TokenList Modifiers
    {
        [DebuggerStepThrough]
        get
        {
            return m_modifiers;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_modifiers = value;
        }
    }

    
Topic.NamespaceName Property

The namespace that contains the member documented by this topic, if applicable; for example, "Abc.Def". null if none or not applicable. null for TopicKind.NamespaceTopic topics; MemberName is the namespace name of a namespace topic (String.Empty for the global namespace).

    public TokenList NamespaceName
    {
        [DebuggerStepThrough]
        get
        {
            return m_namespaceName;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_namespaceName = value;
        }
    }

    
Topic.NamespaceTopic Property

The TopicKind.NamespaceTopic topic that refers to the namespace that contains the member documented by this topic, if applicable. null if none or not applicable. null for TopicKind.NamespaceTopic topics.

    public NamespaceTopic NamespaceTopic
    {
        [DebuggerStepThrough]
        get
        {
            return m_namespaceTopic;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_namespaceTopic = value;
        }
    }

    
Topic.ParentTypeName Property

Gets the name of the class, struct, or enum that contains the member documented by this topic, if applicable; for example, "Abc.Def" in the case of enum "Def" nested within "Abc". Includes type parameters for each ancestor type. null if none or not applicable.

    public TokenList ParentTypeName
    {
        get
        {
            if ((ParentTopic == null) ||
                (TopicKind == TopicKind.NamespaceTopic))
                return null;
            TokenList tokenList = new TokenList();
            if (ParentTopic.CopyTypeName(tokenList))
                return tokenList;
            else
                return null;
        }
    }

    
Topic.MemberType Property

The type of the member documented by this topic, if applicable; for example, "Ghi" (in the case of constant, field, etc. named "Ghi"). For method topics, this is the return type. For namespace topics, this is the fully-qualified namespace name. null if none or not applicable (for example, for Topic objects that document a type).

    public TokenList MemberType
    {
        [DebuggerStepThrough]
        get
        {
            return m_memberType;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_memberType = value;
        }
    }

    
Topic.ExplicitPrefix Property

For members that are explicit interface implementations (e.g. "IDisposable.Dispose"), this is the prefix before the member name (e.g. "IDisposable."). For other members, this is null.

    public TokenList ExplicitPrefix
    {
        [DebuggerStepThrough]
        get
        {
            return m_explicitPrefix;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_explicitPrefix = value;
        }
    }

    
Topic.MemberName Property

The name of the member documented by this topic, if applicable; examples: "Ghi" (in the case of class, struct, interface, event, delegate, enum, method, property, etc. named "Ghi"); "operator +" (in the case of an operator). null if none or not applicable.

Remarks

For members that are explicit interface implementations (e.g. "IDisposable.Dispose"), only the actual member name (e.g. "Dispose") is MemberName) -- the rest is ExplicitPrefix.

    public string MemberName
    {
        [DebuggerStepThrough]
        get
        {
            return m_memberName;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_memberName = value;
        }
    }

    
Topic.TypeParameters Property

The type parameters of the member documented by this topic, if applicable; for example, "T" and "U" for type parameter declaration "<T,U>", and "string" and "List<int>" for the type parameter declaration "<string, List<int>>". null if none or not applicable.

    public TokenList[] TypeParameters
    {
        [DebuggerStepThrough]
        get
        {
            return m_typeParameters;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_typeParameters = value;
        }
    }

    
Topic.BaseTypes Property

The base types of the member documented by this topic, if applicable; for example, "List<T>" and "IDisposable" in class declaration "class Abc : List<T>, IDisposable { ... }". null if none or not applicable.

    public TokenList[] BaseTypes
    {
        [DebuggerStepThrough]
        get
        {
            return m_baseTypes;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_baseTypes = value;
        }
    }

    
Topic.BaseClassTopic Property

The Topic that is the base class if this topic. null if none or not applicable (for example, if this topic is not a TopicKind.ClassTopic topic).

    public Topic BaseClassTopic
    {
        [DebuggerStepThrough]
        get
        {
            return m_baseClassTopic;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_baseClassTopic = value;
        }
    }

    
Topic.Constraints Property

The "where" clause list of the member documented by this topic, if applicable; for example, "where T : IDisposable where U : struct { ... }". null if none or not applicable.

    public TokenList Constraints
    {
        [DebuggerStepThrough]
        get
        {
            return m_constraints;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_constraints = value;
        }
    }

    
Topic.Parameters Property

Gets the parameters of the member documented by this topic, if applicable, i.e. if the member is a method or indexer; null if none or not applicable. Note that if this member has a parameter list but that parameter list is empty then an empty collection is returned.

    public IList<Parameter> Parameters
    {
        [DebuggerStepThrough]
        get
        {
            if (m_parameters == null)
                return null;
            else
                return new ReadOnlyCollection<Parameter>(m_parameters);
        }
    }

    
Topic.ParametersArray Property

Gets a copy of Parameters as an array. null if none or not applicable.

    public Parameter[] ParametersArray
    {
        get
        {
            if ((m_parameters == null) || (m_parameters.Count == 0))
                return null;
            else
                return m_parameters.ToArray();
        }
    }

    
Topic.ParametersList Property

Gets or sets Parameters as a writable list.

    internal List<Parameter> ParametersList
    {
        [DebuggerStepThrough]
        get
        {
            return m_parameters;
        }
        [DebuggerStepThrough]
        set
        {
            m_parameters = value;
        }
    }

    
Topic.MethodKind Property

What kind of method this is (if any). MethodKind.NotAMethod if none or not applicable.

    public MethodKind MethodKind
    {
        [DebuggerStepThrough]
        get
        {
            return m_methodKind;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_methodKind = value;
        }
    }

    
Topic.PropertyKind Property

What kind of property this is (if any). PropertyKind.NotAProperty if none or not applicable.

    public PropertyKind PropertyKind
    {
        [DebuggerStepThrough]
        get
        {
            return m_propertyKind;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_propertyKind = value;
        }
    }

    
Topic.EnumValueNames Property

Gets the names of the values declared in this enum, if this is an enum; for example, "Yes" and "No" in "enum Answer { Yes, No }". null if none or not applicable.

    public IList<string> EnumValueNames
    {
        [DebuggerStepThrough]
        get
        {
            if ((m_enumValueNames == null) || (m_enumValueNames.Count == 0))
                return null;
            else
                return new ReadOnlyCollection<string>(m_enumValueNames);
        }
    }

    
Topic.EnumValueNamesArray Property

Gets a copy of EnumValueNames as an array. null if none or not applicable.

    public string[] EnumValueNamesArray
    {
        get
        {
            if ((m_enumValueNames == null) || (m_enumValueNames.Count == 0))
                return null;
            else
                return m_enumValueNames.ToArray();
        }
    }

    
Topic.EnumValueNamesList Property

Gets or sets EnumValueNames as a writable list.

    internal List<string> EnumValueNamesList
    {
        [DebuggerStepThrough]
        get
        {
            return m_enumValueNames;
        }
        [DebuggerStepThrough]
        set
        {
            m_enumValueNames = value;
        }
    }

    
Topic.Attributes Property

Gets a list of attributes, such as "Bar(X=15, Y=67)" within "[Foo(123), Bar(X=45, Y=67)]", of this member. null if none or not applicable.

    public IList<TokenList> Attributes
    {
        [DebuggerStepThrough]
        get
        {
            if ((m_attributes == null) || (m_attributes.Count == 0))
                return null;
            else
                return new ReadOnlyCollection<TokenList>(m_attributes);
        }
    }

    
Topic.GetAccessor Property

Gets information about the "get" accessor if this the declaration of a property that has a "get" accessor. null if none or not applicable.

    public Accessor GetAccessor
    {
        [DebuggerStepThrough]
        get
        {
            return m_getAccessor;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_getAccessor = value;
        }
    }

    
Topic.SetAccessor Property

Gets information about the "set" accessor if this the declaration of a property that has a "set" accessor. null if none or not applicable.

    public Accessor SetAccessor
    {
        [DebuggerStepThrough]
        get
        {
            return m_setAccessor;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_setAccessor = value;
        }
    }

    
Topic.UsingContext Property

Gets the "using" directive information associated with this topic.

    public UsingContext UsingContext
    {
        [DebuggerStepThrough]
        get
        {
            return m_usingContext;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_usingContext = value;
        }
    }

    
Topic.ChildTopics Property

Gets the list of topics for which this topic is specified as the ParentTopic. Returns an empty collection if there are no child topics.

    public IList<Topic> ChildTopics
    {
        [DebuggerStepThrough]
        get
        {
            if (m_childTopics == null)
                return new ReadOnlyCollection<Topic>(new List<Topic>());
            else
                return new ReadOnlyCollection<Topic>(m_childTopics);
        }
    }

    
Topic.MemberTopics Property

Enumerates the topics which should appear in this topics list of member topics. If this topic is a TopicKind.ClassTopic, the enumeration includes members of the base class, and that class's base class, and so on, including only documented classes (not System.Object, for example). An ancestor class member is not included if it is overridden by a descendent up to and including this class.

Remarks

Classes are searched for inherited members, but structs are not (since structs don't support inheritance), and interfaces are not (since conventionally inherited members are not documented for interfaces).

    public IEnumerable<MemberInfo> MemberTopics
    {
        get
        {
            // first, yield all documented non-overload-list topics that are
            // children of this topic; keep track of the signature of yielded
            // topics in <signatures>
            Dictionary<string, bool> signatures;
            if (TopicKind == TopicKind.ClassTopic)
                signatures = new Dictionary<string, bool>(20);
            else
                signatures = null;
            foreach (Topic memberTopic in ChildTopics)
            {
                if (!memberTopic.IsDocumented ||
                        (memberTopic is OverloadListTopic))
                    continue;
                yield return new MemberInfo(memberTopic, null);
                if (TopicKind == TopicKind.ClassTopic)
                {
                    string signature = memberTopic.GetOverloadingSignature();
                    if (signature != null)
                        signatures[signature] = true;
                }
            }

            // if this topic isn't a class topic, we're done
            if (TopicKind != TopicKind.ClassTopic)
                yield break;

            // loop once for each ancestor class
            Topic baseClassTopic = BaseClassTopic;
            int inherited = 0;
            while (baseClassTopic != null)
            {
                // yield topics that should be added to the list of member
                // topics, i.e. documented non-overload-list property or method
                // topics (excluding constructors and destructors) that are
                // public or protected and which don't have a signature of a
                // topic we've already yielded
                foreach (Topic memberTopic in baseClassTopic.ChildTopics)
                {
                    if (!memberTopic.IsDocumented)
                        continue; // not a documented topic
                    if (memberTopic is OverloadListTopic)
                        continue; // skip overload list topics
                    if (!memberTopic.HasModifier("public", "protected"))
                        continue; // not public or protected
                    string signature = memberTopic.GetOverloadingSignature();
                    if (signature == null)
                        continue; // not an overloadable property or method
                    bool unused;
                    if (signatures.TryGetValue(signature, out unused))
                        continue; // overridden
                    yield return new MemberInfo(memberTopic, baseClassTopic);
                    signatures.Add(signature, true);
                    inherited++;
                }

                // continue up the inheritance tree
                baseClassTopic = baseClassTopic.BaseClassTopic;
            }

            // for debugging purposes: display the number of inherited members
#if false && DEBUG
            if (inherited > 0)
            {
                Console.WriteLine("{0}: inherited {1} members", this,
                    inherited);
            }
#endif
        }
    }

    
Topic.DescendentTopics Property

Enumerates the topics for which this topic is specified as the ParentTopic or the Topic.ParentTopic and so on. Returns an empty enumeration if there are no descendent topics. Note that "decendent" here refers to nesting, not derivation.

    public IEnumerable<Topic> DescendentTopics
    {
        get
        {
            foreach (Topic childTopic in ChildTopics)
            {
                yield return childTopic;
                foreach (Topic descendentTopic in childTopic.DescendentTopics)
                    yield return descendentTopic;
            }
        }
    }

    
Topic.IsTypeTopic Property

Returns true if this is a type topic, i.e. a topic that is listed in NamespaceTopic.TypeTopics.

    public bool IsTypeTopic
    {
        [DebuggerStepThrough]
        get
        {
            return m_isTypeTopic;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_isTypeTopic = value;
        }
    }

    
Topic.IsDocumented Property

Gets or sets a value indicating if this is a documented topic, i.e. a topic for which documentation is supposed to be generated.

    public bool IsDocumented
    {
        [DebuggerStepThrough]
        get
        {
            return m_isDocumented;
        }
        [DebuggerStepThrough]
        set
        {
            m_isDocumented = value;
        }
    }

    
Topic.CanLinkTo Property

Returns true if this topic can be hyperlinked to. Topics that have IsDocumented equal to true or that are enumeration value topics with documented parent enumeration topics can be linked to. (In the latter case, no documenation is generated for the enumeration value topic -- hyperlinks are directed to the parent enumeration topic.)

    public bool CanLinkTo
    {
        get
        {
            return IsDocumented ||
                ((TopicKind == TopicKind.EnumValueTopic) &&
                 (ParentTopic != null) &&
                 (ParentTopic.TopicKind == TopicKind.EnumTopic) &&
                 ParentTopic.IsDocumented);
        }
    }

    
Topic.OverloadListTopic Property

Returns the OverloadListTopic for this topic, if this topic is an overload, i.e. if there are other topics with the same BaseName. Returns null otherwise.

    public OverloadListTopic OverloadListTopic
    {
        [DebuggerStepThrough]
        get
        {
            return m_overloadListTopic;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_overloadListTopic = value;
        }
    }

    
Topic.AttributesArray Property

Gets a copy of Attributes as an array. null if none or not applicable.

    public TokenList[] AttributesArray
    {
        get
        {
            if ((m_attributes == null) || (m_attributes.Count == 0))
                return null;
            else
                return m_attributes.ToArray();
        }
    }

    
Topic.AttributesList Property

Gets or sets Attributes as a writable list.

    internal List<TokenList> AttributesList
    {
        [DebuggerStepThrough]
        get
        {
            return m_attributes;
        }
        [DebuggerStepThrough]
        set
        {
            m_attributes = value;
        }
    }

    
Topic.TopicKindCSharpKeyword Property

Returns the C# declaration term (e.g. "class") corresponding to TopicKind (e.g. TopicKind.ClassTopic).

    public string TopicKindCSharpKeyword
    {
        get
        {
            switch (TopicKind)
            {
            case TopicKind.NamespaceTopic:
                return "namespace";
            case TopicKind.ClassTopic:
                return "class";
            case TopicKind.StructTopic:
                return "struct";
            case TopicKind.InterfaceTopic:
                return "interface";
            case TopicKind.EventTopic:
                return "event";
            case TopicKind.DelegateTopic:
                return "delegate";
            case TopicKind.EnumTopic:
                return "enum";
            case TopicKind.UnknownTopic:
                return "unknown";
            default:
                return TopicKind.ToString();
            }
        }
    }

    
Topic.TopicKindTitle Property

Returns a title-case label (for example, "Class" or "Structure") corresponding to a given TopicKind.

    public string TopicKindTitle
    {
        get
        {
            switch (TopicKind)
            {
            case TopicKind.NamespaceTopic:
                return Resources.NamespaceTopicTitle;
            case TopicKind.ClassTopic:
                return Resources.ClassTopicTitle;
            case TopicKind.StructTopic:
                return Resources.StructTopicTitle;
            case TopicKind.InterfaceTopic:
                return Resources.InterfaceTopicTitle;
            case TopicKind.EventTopic:
                return Resources.EventTopicTitle;
            case TopicKind.DelegateTopic:
                return Resources.DelegateTopicTitle;
            case TopicKind.EnumTopic:
                return Resources.EnumTopicTitle;
            case TopicKind.EnumValueTopic:
                return Resources.EnumValueTopicTitle;
            case TopicKind.MethodTopic:
                return Resources.MethodTopicTitle;
            case TopicKind.PropertyTopic:
                return Resources.PropertyTopicTitle;
            case TopicKind.FieldTopic:
                return Resources.FieldTopicTitle;
            default:
                return Resources.UnknownTopicTitle;
            }
        }
    }

    
Topic.QualifiedMemberName Property

Gets the member name with the namespace name and parent class name (if any) prepended.

    public TokenList QualifiedMemberName
    {
        get
        {
            TokenList result = new TokenList();
            ConstructQualifiedMemberName(result, true, true, false);
            if (result.IsEmpty)
                return null;
            else
                return result;
        }
    }

    
Topic.QualifiedMemberNameWithoutNamespace Property

Gets the member name with the parent class name (if any) prepended, but without the parent namespace name prepended.

    public TokenList QualifiedMemberNameWithoutNamespace
    {
        get
        {
            TokenList result = new TokenList();
            ConstructQualifiedMemberName(result, false, true, false);
            if (result.IsEmpty)
                return null;
            else
                return result;
        }
    }

    
Topic.CanonicalName Property

Gets the canonical name of this topic. CanonicalName is the same as QualifiedMemberName except that type parameter names are removed from the name. For example, if QualifiedMemberName is "Foo<T,U>.Bar", CanonicalName is "Foo<,>.Bar".

Remarks

Consider a class MyNs.Outer<T>.Inner<U,V>.Inner2, i.e. a class named Inner2 nested inside the class named Inner that has two type parameters, itself nested inside a class named Outer in namespace MyNs. This class (Inner2) has a canonical name of "MyNs.Outer<>.Inner<,>.Inner2". (Note that type parameter names are removed, since they do not contribute to the resolution of a type name to a topic.) Now suppose a method, Foo is declared as having a return type of Outer<MyList>.Inner<MyPoint<bool>?,int[,]>.Inner2[]. When CodeDoc attempts to look up the topic associated with this type, it "canonicalizes" it, removing the type arguments and the trailing array specifier, resulting in the a canonical name of "Outer<>.Inner<,>.Inner2". Assuming Inner2 is accessible from where Foo is declared (e.g. Foo is in the MyNs namespace, or MyNs is declared using a using declaration), then CodeDoc will be able to construct a hyperlink from "Inner2" (in the return type of Foo) to the "Inner2" topic.

As shown in the example above, the canonical name of a type with type parameters includes the type parameters (except with type parameter names removed). However, the canonical name of a method with type parameters does not include the type parameters. For example, a method MyNs.MyClass.Bar<T>(T arg) has canonical name "MyNs.MyClass.Bar", not "MyNs.MyClass.Bar<>". The reason is primarily convenience: if a method with type parameters included the type parameters in the canonical name, then all reference to the method would need to include the type parameters. For example, a hyperlink to the method's topic from within XML documentation would need to be <r>Bar&lt;&gt;</r>, not simply <r>Bar</r>. You may wonder: why doesn't the convenience argument apply to types like it does to methods? The reason is that CodeDoc needs to create precise references to type topics at times: for example, a topic corresponding to a class declared with a base class of Abc needs to list the the inherited members of Abc, and that requires knowing the difference between Abc, Abc<T>, Abc<T,U>, etc.

While a method's type parameters are excluded from the method's canonical name, the type parameters of the type of the method are not. For example, method MyNs.MyClass<Q>.Bar<T>(T arg) has canonical name "MyNs.MyClass<>.Bar".

CanonicalizeMemberName can be used to convert a type name (e.g. "Outer<T>.Inner<U,V>.Inner2") or type reference (e.g. "Outer<MyList>.Inner<MyPoint<bool>?,int[,]>.Inner2") to its canonical form (e.g. "Outer<>.Inner<,>.Inner2").

The DocumentationSet.DuplicateCanonicalName event is fired if it's discovered that two topics have the same canonical name.

    public TokenList CanonicalName
    {
        get
        {
            // set <result> to the canonicalized version of
            // <QualifiedMemberName>
            TokenList result = CanonicalizeMemberName(
                QualifiedMemberName, !IsTypeTopic);

            // if this is a type with type parameters, append their
            // canonicalized representation, e.g. "<,,>"
            if (IsTypeTopic && (m_typeParameters != null))
            {
                result.Append(new Token(SourceFile.LAngle));
                for (int i = 0; i < m_typeParameters.Length - 1; i++)
                    result.Append(new Token(','));
                result.Append(new Token(SourceFile.RAngle));
            }

            return result;
        }
    }

    
Topic.BaseName Property

Gets the base porton of the Name property, i.e. the part that is not necessarily unique among all topics. BaseName is based on QualifiedMemberName -- two topics with the same QualifiedMemberName and the same TopicKind will have the same BaseName.

Remarks

For example, "MyNamespace.Foo.Bar", i.e. method "Bar" in class "Foo" in namespace "MyNamespace", might be a QualifiedMemberName; "MyNamespace.Foo.Bar.Method" would be the corresponding BaseName.

    public string BaseName
    {
        get
        {
            return String.Format("{0}.{1}",
                MakeValidFileName(QualifiedMemberName.ToString()),
                TopicKindTitle.Replace(" ", ""));
        }
    }

    
Topic.Name Property

Gets the name of this topic which is unique among all topics in the documentation set. Since Name is unique, it can be used in a file name. Name is only valid after DocumentationSet.BeginUsingSources has been called (either directly or indirectly).

Remarks

Name is the same as BaseName, except that if two topics would have the same BaseName then a numeric suffix, e.g. ".1", ".2", and so on, is appended to Name to make Name unique. Since DocumentationSet.BeginUsingSources is the method that checks for uniqueness, DocumentationSet.BeginUsingSources must be called in order to initialize Name.

    public string Name
    {
        [DebuggerStepThrough]
        get
        {
            return m_name;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_name = value;
        }
    }

    
Topic.Id Property

Gets the integer identifier of this topic which is unique among all topics in the documentation set. Id is only valid after DocumentationSet.BeginUsingSources has been called (either directly or indirectly).

    public int Id
    {
        [DebuggerStepThrough]
        get
        {
            return m_id;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_id = value;
        }
    }

    
Topic.DocHtmlFileName Property

Gets the name of the HTML file that contains, or will contain, the documentation for this topic.

Remarks

DocHtmlFileName is based on Name. For example, Name value "MyNamespace.Foo.Bar.2.Method" (i.e. the second overload of method "Bar" in class "Foo" in namespace "MyNamespace") corresponds to DocHtmlFileName value "MyNamespace.Foo.Bar.Method.2.htm".

    public string DocHtmlFileName
    {
        get
        {
            return Name + ".htm";
        }
    }

    
Topic.CodeHtmlBlockBookmark Property

Gets the HTML bookmark name of this topic, used as the HTML anchor name when this topic is embedded in formatted code; for example, "Topic123" (based on Id).

    public string CodeHtmlBlockBookmark
    {
        get
        {
            return String.Format("Topic{0}", Id);
        }
    }

    
Topic.CodeHtmlUrl Property

Gets the URL to the documentation block (i.e. documentation embedded in formatted code HTML) of this topic, relative to the formatted code directory; for example, "Foo!Bar.cs.htm#Topic123". Returns null if there is no SourceFile associated with this topic.

    public string CodeHtmlUrl
    {
        get
        {
            if (TopicKind == TopicKind.NamespaceTopic)
                return CodeNamespaceHtmlFileName;
            else
            if (this is OverloadListTopic)
                return CodeOverloadListHtmlFileName;
            else
            if (TopicKind == TopicKind.NamespaceTopic)
                return CodeNamespaceHtmlFileName;
            else
            if (SourceFile == null)
                return null;
            else
            {
                return String.Format("{0}#{1}", SourceFile.CodeHtmlFileName,
                    CodeHtmlBlockBookmark);
            }
        }
    }

    
Topic.CodeNamespaceHtmlFileName Property

If this is an namespace topic, this property returns the name of the code namespace HTML file, i.e. the HTML document that lists the contents of the namespace and provides links to the formatted source code files. Returns null if this is not an namespace topic.

    public string CodeNamespaceHtmlFileName
    {
        get
        {
            if (this is NamespaceTopic)
                return String.Format("{0}.CodeNamespace.htm", Name);
            else
                return null;
        }
    }

    
Topic.CodeOverloadListHtmlFileName Property

If this is an overload list topic, this property returns the name of the code overload list HTML file, i.e. the HTML document that lists the overloads and provides links to the documentation block of each overload. Returns null if this is not an overload list topic.

    public string CodeOverloadListHtmlFileName
    {
        get
        {
            if (this is OverloadListTopic)
                return String.Format("{0}.CodeOverload.htm", Name);
            else
                return null;
        }
    }

    
Topic.IsGlobalNamespace Property

Returns true if this topic refers to the global namespace, false if not.

    public bool IsGlobalNamespace
    {
        get
        {
            return (TopicKind == TopicKind.NamespaceTopic) &&
                (MemberName.Length == 0);
        }
    }

    
Topic.VeryShortTitleNoKind Property

Returns a short title for this topic, not including the class name, parent class name, or parent namespace name (if any), and not including the topic kind (e.g. "Method"). Type parameters and regular parameters are included if this is an overload topic (i.e. a topic for which there are other topics with the same BaseName).

    public string VeryShortTitleNoKind
    {
        get
        {
            if (IsGlobalNamespace)
                return Resources.GlobalNamespace;
            TokenList name = new TokenList();
            ConstructQualifiedMemberName(name, false, false, true);
            if (name.IsEmpty)
                return TopicKindTitle;
            else
                return GetTitle(name.ToString(), false);
        }
    }

    
Topic.VeryShortTitle Property

Returns a short title for this topic, not including the class name, parent class name, or parent namespace name (if any). Type parameters and regular parameters are included if this is an overload topic (i.e. a topic for which there are other topics with the same BaseName).

    public string VeryShortTitle
    {
        get
        {
            if (IsGlobalNamespace)
                return Resources.GlobalNamespace;
            TokenList name = new TokenList();
            ConstructQualifiedMemberName(name, false, false, true);
            if (name.IsEmpty)
                return TopicKindTitle;
            else
                return GetTitle(name.ToString(), true);
        }
    }

    
Topic.ShortTitle Property

Returns a short title for this topic, including the class name and parent class names, if any, but not including the parent namespace name. Type parameters and regular parameters are included if this is an overload topic (i.e. a topic for which there are other topics with the same BaseName).

    public string ShortTitle
    {
        get
        {
            if (IsGlobalNamespace)
                return Resources.GlobalNamespace;
            TokenList name = new TokenList();
            bool includeParentType =
                ((TopicKind != TopicKind.MethodTopic) ||
                 !((MethodKind == MethodKind.Constructor) ||
                   (MethodKind == MethodKind.Destructor)));
            ConstructQualifiedMemberName(name, false, includeParentType, true);
            if (name.IsEmpty)
                return TopicKindTitle;
            else
                return GetTitle(name.ToString(), true);
        }
    }

    
Topic.LongTitle Property

Returns a title for this topic, including the class name and fully qualified parent class names, if any, including the parent namespace name. Type parameters and regular parameters are included if this is an overload topic (i.e. a topic for which there are other topics with the same BaseName).

    public string LongTitle
    {
        get
        {
            if (IsGlobalNamespace)
                return Resources.GlobalNamespace;
            TokenList name = new TokenList();
            ConstructQualifiedMemberName(name, true, true, true);
            if (name.IsEmpty)
                return TopicKindTitle;
            else
                return GetTitle(name.ToString(), true);
        }
    }

    
Topic.ShortSignature Property

Returns a short signature for this topic, including the class name and parent class names, if any, but not including the parent namespace name. Does not include the topic kind, e.g. "Method". Type parameters and regular parameters are included if this is an overload topic (i.e. a topic for which there are other topics with the same BaseName).

    public string ShortSignature
    {
        get
        {
            TokenList name = new TokenList();
            ConstructQualifiedMemberName(name, false, true, true);
            if (name.IsEmpty)
                return TopicKindTitle;
            else
                return GetTitle(name.ToString(), false);
        }
    }

    
Topic.LongSignature Property

Returns a signature for this topic, including the class name and fully qualified parent class names, if any, including the parent namespace name. Does not include the topic kind, e.g. "Method". Type parameters and regular parameters are included if this is an overload topic (i.e. a topic for which there are other topics with the same BaseName).

    public string LongSignature
    {
        get
        {
            TokenList name = new TokenList();
            ConstructQualifiedMemberName(name, true, true, true);
            if (name.IsEmpty)
                return TopicKindTitle;
            else
                return GetTitle(name.ToString(), false);
        }
    }

    
Topic.Location Property

Return a human-readable string describing where this topic is within source code.

    public string Location
    {
        get
        {
            if (SourceFile != null)
            {
                return String.Format("{0}({1})",
                    SourceFile.SourceFileAbsolutePath,
                    GetDeclarationLineNumber());
            }
            else
            if (Name != null)
                return Name;
            else
                return BaseName;
        }
    }

    
Topic.XmlCommentSections Property

Enumerates through the top-level sections (for example, "<summary>" and "<param>") of the contents of the Xml property.

    public IEnumerable<XmlCommentSection> XmlCommentSections
    {
        get
        {
            if (Xml == null)
                yield break;
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;
            settings.ConformanceLevel = ConformanceLevel.Fragment;
            settings.LineNumberOffset = FirstXmlComment.GetLineNumber() - 1;
            using (StringReader stringReader = new StringReader(Xml))
            {
                using (XmlReader xmlReader = XmlReader.Create(stringReader,
                        settings))
                {
                    while (true)
                    {
                        try
                        {
                            if (!xmlReader.Read())
                                break;
                        }
                        catch (XmlException ex)
                        {
                            throw NewParsingException(
                                Resources.InvalidXmlComment, ex.Message);
                        }

                        if (xmlReader.NodeType == XmlNodeType.Element)
                        {
                            // this XML element should be an XML comment
                            // section start element such as "<summary>" or
                            // "<param>"
                            XmlCommentSection section =
                                new XmlCommentSection(this, xmlReader);
                            yield return section;
                            try
                            {
                                section.ReadToEnd();
                            }
                            catch (XmlException ex)
                            {
                                throw NewParsingException(
                                    Resources.InvalidXmlComment, ex.Message);
                            }
                        }
                        else
                        if (xmlReader.NodeType == XmlNodeType.Text)
                        {
                            // there shouldn't be any text outside of XML
                            // comment sections
                            throw NewParsingException(xmlReader,
                                Resources.TextOutsideXmlCommentSection,
                                SourceFile.Ellipsis(xmlReader.Value, 50));
                        }
                    }
                }
            }
        }
    }

    
Topic.HasSummaryHtml Property

Returns true if this topic has a "<summary>" section for which HTML has been generated.

    public bool HasSummaryHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.Summary);
        }
    }

    
Topic.HasReturnsHtml Property

Returns true if this topic has a "<returns>" section for which HTML has been generated.

    public bool HasReturnsHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.Returns);
        }
    }

    
Topic.HasValueHtml Property

Returns true if this topic has a "<value>" section for which HTML has been generated.

    public bool HasValueHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.Value);
        }
    }

    
Topic.HasExceptionsHtml Property

Returns true if this topic has "<exceptons>" section(s) for which HTML has been generated.

    public bool HasExceptionsHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.Exception);
        }
    }

    
Topic.HasPermissionsHtml Property

Returns true if this topic has "<permission>" section(s) for which HTML has been generated.

    public bool HasPermissionsHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.Permission);
        }
    }

    
Topic.HasRemarksHtml Property

Returns true if this topic has "<remarks>" section(s) for which HTML has been generated.

    public bool HasRemarksHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.Remarks);
        }
    }

    
Topic.HasExampleHtml Property

Returns true if this topic has "<example>" section(s) for which HTML has been generated.

    public bool HasExampleHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.Example);
        }
    }

    
Topic.HasSeeAlsoHtml Property

Returns true if this topic has "<seealso>" section(s) for which HTML has been generated.

    public bool HasSeeAlsoHtml
    {
        get
        {
            return HasXmlCommentSectionHtml(XmlCommentSectionKind.SeeAlso);
        }
    }

    
Topic.IsExternallyAccessible Property

Returns true if the member defined by this topic is accessible outside of this program or library.

    public bool IsExternallyAccessible
    {
        get
        {
            OverloadListTopic overloadListTopic;
            if ((overloadListTopic = this as OverloadListTopic) != null)
            {
                // overload list topics are accessible if at least one of their
                // overload topics are accessible
                foreach (Topic topic in overloadListTopic.OverloadTopics)
                {
                    if (topic.IsExternallyAccessible)
                        return true;
                }
                return false;
            }
            else
            {
                // regular topics are accessible based on their modifiers and
                // their ancestors' modifiers
                Topic topic = this;
                while (true)
                {
                    bool isInterfaceMember =
                        ((topic.ParentTopic != null) &&
                         (topic.ParentTopic.TopicKind ==
                          TopicKind.InterfaceTopic));
                    if (!topic.HasModifier("public", "protected") &&
                        !isInterfaceMember)
                        return false;
                    topic = topic.ParentTopic;
                    if (topic == null)
                        break;
                    if (topic.TopicKind == TopicKind.NamespaceTopic)
                        break;
                }
                return true;
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    
Topic.SortChildTopics Method
    public void SortChildTopics()
    {
        if (m_childTopics != null)
            m_childTopics.Sort();
    }

    
Topic.GetDeclarationLineNumber Method

Returns the line number that the declaration begins on.

    public int GetDeclarationLineNumber()
    {
        Debug.Assert(StartOfDeclaration != null);
        if (StartOfDeclaration == null) // just in case
            return 0;
        else
            return StartOfDeclaration.GetLineNumber();
    }

    
Topic.ToString Method
    public override string ToString()
    {
        return QualifiedMemberName.ToString();
    }

    
Topic.CanonicalizeMemberName Method (TokenList, bool)

Converts a qualified member name (i.e. the same value used in Topic.QualifiedMemberName) into a canonicalized member name, which is the same except that type parameter names are removed. For example, "Foo<T,U>.Bar" is converted to "Foo<,>.Bar".

Parameters

memberName

The input qualified member name.

removeTrailingTypeParameters

If true, type parameters of the member are removed. This only applies to type parameters of the member itself, not type(s) the member is nested within. For example, input member name "Foo<T,U>.Bar<V>" is canonicalized as "Foo<,>.Bar" if removeTrailingTypeParameters is true.

Remarks

Type parameter names are removed from all type parameters in memberName. Additionally, if removeTrailingTypeParameters is true, any "trailing type parameters" are removed entirely -- see the Remarks section of QualifiedMemberName for an explanation.

    public static TokenList CanonicalizeMemberName(
        TokenList memberName, bool removeTrailingTypeParameters)
    {
        // do nothing if <memberName> is null
        if (memberName == null)
            return null;

        // if <memberName> doesn't contain type parameters, return it
        // as-is
        if (memberName.HeadToken.Next.FindCharacterToken(
                SourceFile.LAngle) == null)
            return memberName;

        // set <result> to a copy of <memberName> with type parameter
        // names removed
        TokenList result = new TokenList();
        int angleNesting = 0; // in "<...>"
        int squareNesting = 0; // in "[...]" -- ignore arrays, e.g. "[,]"
        Token trailingTypeParameter = null;
        foreach (Token token in memberName)
        {
            if (token.IsCharacter(SourceFile.LAngle))
            {
                if (angleNesting == 0)
                {
                    Token newToken = new Token(SourceFile.LAngle);
                    trailingTypeParameter = newToken;
                    result.Append(newToken);
                }
                angleNesting++;
            }
            else
            if (token.IsCharacter(SourceFile.RAngle))
            {
                angleNesting--;
                if (angleNesting == 0)
                    result.Append(new Token(SourceFile.RAngle));
            }
            else
            if (token.IsCharacter(SourceFile.LSquare))
                squareNesting++;
            else
            if (token.IsCharacter(SourceFile.RSquare))
                squareNesting--;
            else
            if (angleNesting == 0)
            {
                result.Append(token.Clone());
                trailingTypeParameter = null;
            }
            else
            if (token.IsCharacter(',') && (squareNesting == 0) &&
                    (angleNesting == 1))
                result.Append(token.Clone());
        }
        Debug.Assert(angleNesting == 0);
        Debug.Assert(squareNesting == 0);

        // remove trailing type parameters, if any (if specified)
        if (removeTrailingTypeParameters &&
            (trailingTypeParameter != null) &&
            !trailingTypeParameter.Next.IsTail)
        {
            TokenList.ExtractTokens(trailingTypeParameter,
                result.TailToken.Previous);         
        }

        return result;
    }

    
Topic.CanonicalizeMemberName Method (string, bool)

Converts a member name into a canonicalized member name, which is the same except that type parameter names, square brackets, etc. are removed. For example, "Foo<T,U>.Bar" is converted to "Foo<,>.Bar".

Parameters

memberName

The input qualified member name.

removeTrailingTypeParameters

If true, type parameters of the member are removed. This only applies to type parameters of the member itself, not type(s) the member is nested within. For example, input member name "Foo<T,U>.Bar<V>" is canonicalized as "Foo<,>.Bar" if removeTrailingTypeParameters is true.

Remarks

Type parameter names are removed from all type parameters in memberName. Additionally, if removeTrailingTypeParameters is true, any "trailing type parameters" are removed entirely -- see the Remarks section of QualifiedMemberName for an explanation.

    public static string CanonicalizeMemberName(
        string memberName, bool removeTrailingTypeParameters)
    {
        // do nothing if <memberName> is null
        if (memberName == null)
            return null;

#if false
        // if <memberName> doesn't contain type parameters, return it
        // as-is
        if (memberName.IndexOf(SourceFile.LAngle) < 0)
            return memberName;
#endif

        // set <result> to a copy of <memberName> with type parameter
        // names removed
        StringBuilder result = new StringBuilder(memberName.Length);
        int angleNesting = 0; // in "<...>"
        int squareNesting = 0; // in "[...]" -- ignore arrays, e.g. "[,]"
        int trailingTypeParameterIndex = -1;
        foreach (char ch in memberName)
        {
            if (ch == SourceFile.LAngle)
            {
                if (angleNesting == 0)
                {
                    trailingTypeParameterIndex = result.Length;
                    result.Append(ch);
                }
                angleNesting++;
            }
            else
            if (ch == SourceFile.RAngle)
            {
                angleNesting--;
                if (angleNesting == 0)
                    result.Append(ch);
            }
            else
            if (ch == SourceFile.LSquare)
                squareNesting++;
            else
            if (ch == SourceFile.RSquare)
                squareNesting--;
            else
            if (angleNesting == 0)
            {
                result.Append(ch);
                trailingTypeParameterIndex = -1;
            }
            else
            if ((ch == ',') && (squareNesting == 0) && (angleNesting == 1))
                result.Append(ch);
        }
        Debug.Assert(angleNesting == 0);
        Debug.Assert(squareNesting == 0);

        // remove trailing type parameters, if any (and if specified); return
        // the result
        string resultString = result.ToString();
        if (removeTrailingTypeParameters)
        {
            if (trailingTypeParameterIndex >= 0)
                return resultString.Substring(0, trailingTypeParameterIndex);
            else
                return resultString;
        }
        else
            return resultString;
    }

    
Topic.EnumerateDescendentNonTypes Method

Enumerates the topics for which a given topic is specified as the ParentTopic or the Topic.ParentTopic and so on, excluding type topics (i.e. topics for which IsTypeTopic is true). Returns an empty enumeration if there are no descendent topics.

Parameters

topic

The given topic.

    public static IEnumerable<Topic> EnumerateDescendentNonTypes(Topic topic)
    {
        // yield members of this type topic, but skip type topics
        // since we're already enumerating through all type topics
        foreach (Topic childTopic in topic.ChildTopics)
        {
            if (!childTopic.IsTypeTopic)
            {
                yield return childTopic;
                EnumerateDescendentNonTypes(topic);
            }
        }
    }

    
Topic.HasModifier Method

Returns true if this topic has one of a given set of modifiers (such as "public"), false if not.

Parameters

modifiers

The modifiers to search for. Matching is performed in a case-sensitive manner.

    public bool HasModifier(params string[] modifiers)
    {
        if (m_modifiers == null)
            return false;
        foreach (Token token in m_modifiers)
        {
            foreach (string modifier in modifiers)
            {
                if (token.IsWordOrReservedWord(modifier))
                    return true;
            }
        }
        return false;
    }

    
Topic.HasParameter Method

Returns true if this topic has a parameter with a given name, false if not.

Parameters

parameterName

The name of the type parameter to search for; for example, "fileName". Matching is performed in a case-sensitive manner.

    public bool HasParameter(string parameterName)
    {
        if (Parameters == null)
            return false;
        return (m_parameters.Find(delegate(Parameter parameter)
        {
            return (parameter.ParameterName == parameterName);
        }) != null);
    }

    
Topic.GetParameter Method

Returns the Parameter object corresponding to a given parameter name, or null if there is no parameter with that name.

Parameters

parameterName

The name of the parameter to search for. Matching is performed in a case-sensitive manner.

    public Parameter GetParameter(string parameterName)
    {
        if (m_parameters == null)
            return null;
        return m_parameters.Find(delegate(Parameter parameter)
        {
            return (parameter.ParameterName == parameterName);
        });
    }

    
Topic.GetParameterHtml Method

Gets the HTML corresponding to the "<param>" section of the Xml of this topic corresponding to a given parameter name, or null if none.

Parameters

parameterName

The name of the parameter to search for. Matching is performed in a case-sensitive manner.

    public string GetParameterHtml(string parameterName)
    {
        // do nothing if there is no HTML for any XML comment section
        if (m_xmlSectionsHtml == null)
            return null;

        // set <paramSection> to the "<param>" XmlCommentSection that has a
        // "name" attribute equal to <parameterName>, or null if none
        List<XmlCommentSection> paramSections =
                m_xmlSectionsHtml[(int) XmlCommentSectionKind.Param];
        if (paramSections == null)
            return null;
        XmlCommentSection paramSection = paramSections.Find(
            delegate(XmlCommentSection section)
            {
                return (section.NameAttribute == parameterName);
            });

        // return the HTML of <paramSection>, if any
        if (paramSection != null)
            return paramSection.Html.Trim();
        else
            return null;
    }

    
Topic.HasTypeParameter Method

Returns true if this topic has a type parameter with a given name, false if not.

Parameters

typeParameterName

The name of the type parameter to search for; for example, "T". Matching is performed in a case-sensitive manner.

    public bool HasTypeParameter(string typeParameterName)
    {
        if (TypeParameters == null)
            return false;
        return (Array.Find(TypeParameters, delegate(TokenList typeParameter)
        {
            return (typeParameter.ToString() == typeParameterName);
        }) != null);
    }

    
Topic.GetTypeParameterHtml Method

Gets the HTML corresponding to the "<typeparam>" section of the Xml of this topic corresponding to a given type parameter name, or null if none.

Parameters

typeParameterName

The name of the type parameter to search for. Matching is performed in a case-sensitive manner.

    public string GetTypeParameterHtml(string typeParameterName)
    {
        // do nothing if there is no HTML for any XML comment section
        if (m_xmlSectionsHtml == null)
            return null;

        // set <typeParamSection> to the "<typeparam>" XmlCommentSection that
        // has a "name" attribute equal to <typeParameterName>, or null if none
        List<XmlCommentSection> typeParamSections =
                m_xmlSectionsHtml[(int) XmlCommentSectionKind.TypeParam];
        if (typeParamSections == null)
            return null;
        XmlCommentSection typeParamSection = typeParamSections.Find(
            delegate(XmlCommentSection section)
            {
                return (section.NameAttribute == typeParameterName);
            });

        // return the HTML of <typeParamSection>, if any
        if (typeParamSection != null)
            return typeParamSection.Html.Trim();
        else
            return null;
    }

    
Topic.AddXmlSectionHtml Method

Stores HTML corresponding to a given XML comment section (e.g. "<summary>") of this topic, for later access by methods such as WriteSummaryHtml.

Parameters

section

The XML comment section.

html

The string of HTML to store.

Remarks

This method should only be called by a renderer assembly.

    public void AddXmlSectionHtml(XmlCommentSection section, string html)
    {
        // store <html> in section>
        section.Html = html;

        // create <m_xmlSectionsHtml> if it hasn't been created yet
        if (m_xmlSectionsHtml == null)
        {
            m_xmlSectionsHtml =
                new List<XmlCommentSection>[(int) XmlCommentSectionKind.Length];
        }

        // create the appropriate element of <m_xmlSectionsHtml> if it hasn't
        // been created yet
        int sectionKindInt = (int) section.SectionKind;
        List<XmlCommentSection> list = m_xmlSectionsHtml[sectionKindInt];
        if (list == null)
        {
            list = new List<XmlCommentSection>();
            m_xmlSectionsHtml[sectionKindInt] = list;
        }

        // add <section> to the list
        section.Enumerating = false;
        list.Add(section);
    }

    
Topic.WriteSummaryHtml Method (HtmlTextWriter)

Writes the HTML corresponding to the "<summary>" section of the Xml property of this topic. Does nothing if there is no "<summary>" section.

Parameters

htmlWriter

Where to write the HTML.

    public void WriteSummaryHtml(HtmlTextWriter htmlWriter)
    {
        WriteXmlCommentSectionHtml(XmlCommentSectionKind.Summary, htmlWriter,
            null);
    }

    
Topic.WriteReturnsHtml Method

Writes the HTML corresponding to the "<returns>" section of the Xml property of this topic. Does nothing if there is no "<returns>" section.

Parameters

htmlWriter

Where to write the HTML.

    public void WriteReturnsHtml(HtmlTextWriter htmlWriter)
    {
        WriteXmlCommentSectionHtml(XmlCommentSectionKind.Returns, htmlWriter,
            null);
    }

    
Topic.WriteValueHtml Method

Writes the HTML corresponding to the "<value>" section of the Xml property of this topic. Does nothing if there is no "<value>" section.

Parameters

htmlWriter

Where to write the HTML.

    public void WriteValueHtml(HtmlTextWriter htmlWriter)
    {
        WriteXmlCommentSectionHtml(XmlCommentSectionKind.Value, htmlWriter,
            null);
    }

    
Topic.WriteSummaryHtml Method (HtmlTextWriter, HtmlTextWriterDelegate)

Writes the HTML corresponding to the "<summary>" section of the Xml property of this topic. Does nothing if there is no "<summary>" section. Allows the caller to append additional HTML.

Parameters

htmlWriter

Where to write the HTML.

htmlWriterDelegate

If not null, this delegate is called after the comment section HTML is written, but before the closing paragraph tag is written. This allows the caller to append text.

    public void WriteSummaryHtml(HtmlTextWriter htmlWriter,
        HtmlTextWriterDelegate htmlWriterDelegate)
    {
        WriteXmlCommentSectionHtml(XmlCommentSectionKind.Summary, htmlWriter,
            htmlWriterDelegate);
    }

    
Topic.WriteRemarksHtml Method

Writes the HTML corresponding to the "<remarks>" section of the Xml property of this topic. Does nothing if there is no "<remarks>" section.

Parameters

htmlWriter

Where to write the HTML.

    public void WriteRemarksHtml(HtmlTextWriter htmlWriter)
    {
        WriteXmlCommentSectionHtml(XmlCommentSectionKind.Remarks, htmlWriter,
            null);
    }

    
Topic.WriteExampleHtml Method

Writes the HTML corresponding to the "<example>" section of the Xml property of this topic. Does nothing if there is no "<example>" section.

Parameters

htmlWriter

Where to write the HTML.

    public void WriteExampleHtml(HtmlTextWriter htmlWriter)
    {
        WriteXmlCommentSectionHtml(XmlCommentSectionKind.Example, htmlWriter,
            null);
    }

    
Topic.HasXmlCommentSectionHtml Method

Returns true if this topic has a specified XML comment section (for example, "<summary>") for which HTML has been generated.

Parameters

sectionKind

Identifies the top-level section; for example, "<summary>" or "<remarks>").

    public bool HasXmlCommentSectionHtml(XmlCommentSectionKind sectionKind)
    {
        if (m_xmlSectionsHtml == null)
            return false;
        List<XmlCommentSection> sections =
            m_xmlSectionsHtml[(int) sectionKind];
        return (sections != null) && (sections.Count > 0);
    }

    
Topic.GetRenderedXmlCommentSections Method

Enumerates through the top-level sections of a given section kind (for example, "<summary>" or "<param>") of this topic, among sections that were previously added using AddXmlSectionHtml.

Parameters

sectionKind

Identifies the top-level section; for example, "<summary>" or "<remarks>").

    public IEnumerable<XmlCommentSection> GetRenderedXmlCommentSections(
        XmlCommentSectionKind sectionKind)
    {
        // do nothing if there is no array of XML comment section HTML
        if (m_xmlSectionsHtml == null)
            yield break;

        // set <sections> to the list of sections of this type; do nothing if
        // there is none
        List<XmlCommentSection> sections =
            m_xmlSectionsHtml[(int) sectionKind];
        if ((sections == null) || (sections.Count == 0))
            yield break;

        // yield each section
        foreach (XmlCommentSection section in sections)
            yield return section;
    }

    
Topic.WriteXmlCommentSectionHtml Method

Writes the HTML corresponding to an XML comment section (for example, "<summary>") of the Xml property of this topic. All HTML blocks for this section are concatenated into a series of paragraphs. Does nothing if the specified XML comment section doesn't exist.

Parameters

sectionKind

Identifies the top-level section (for example, "<summary>" or "<remarks>") to write the HTML of.

htmlWriter

Where to write the HTML.

htmlWriterDelegate

If not null, this delegate is called after the comment section HTML is written, but before the closing paragraph tag is written. This allows the caller to append text.

    public void WriteXmlCommentSectionHtml(XmlCommentSectionKind sectionKind,
        HtmlTextWriter htmlWriter, HtmlTextWriterDelegate htmlWriterDelegate)
    {
        foreach (XmlCommentSection section in 
            GetRenderedXmlCommentSections(sectionKind))
        {
            htmlWriter.RenderBeginTag("p");
            string innerHtml = section.Html.Trim();
            htmlWriter.Write(innerHtml);
            if (htmlWriterDelegate != null)
                htmlWriterDelegate(htmlWriter);
            htmlWriter.RenderEndTag();
            htmlWriter.WriteLine();
        }
    }

#if DEBUG
    /// <summary>
    /// Returns debugging information about this topic.
    /// </summary>
    ///
    /// <param name="maxDataLength">Each piece of output data is truncated to
    ///     approximately this length.</param>
    ///
    public string Dump(int maxDataLength)
    {
        StringBuilder result = new StringBuilder(1000);

        result.AppendFormat("----- {0} {1} -----\r\n", TopicKind,
            QualifiedMemberName);

        if (MethodKind != MethodKind.NotAMethod)
            result.AppendFormat("MethodKind: {0}\r\n", MethodKind);

        if (PropertyKind != PropertyKind.NotAProperty)
            result.AppendFormat("PropertyKind: {0}\r\n", PropertyKind);

        if (Attributes != null)
        {
            result.Append("Attributes: ");
            int length = 0;
            foreach (TokenList attribute in Attributes)
            {
                string str = "[" + attribute.ToString() + "]";
                int newLength = length + str.Length;
                if (newLength > maxDataLength)
                {
                    result.AppendFormat("{0}...",
                        str.Substring(0, maxDataLength - length));
                    break;
                }
                else
                    result.Append(str);
                length = newLength;
            }
            result.Append("\r\n");
        }

        if (Modifiers != null)
        {
            result.AppendFormat("Modifiers: {0}\r\n",
                TokenList.ToString(Modifiers, maxDataLength, false));
        }

        if (MemberType != null)
        {
            result.AppendFormat("MemberType: {0}\r\n",
                TokenList.ToString(MemberType, maxDataLength, false));
        }

        if (NamespaceName != null)
            result.AppendFormat("NamespaceName: {0}\r\n", NamespaceName);

        if (ParentTypeName != null)
            result.AppendFormat("ParentTypeName: {0}\r\n", ParentTypeName);

        if (ExplicitPrefix != null)
        {
            result.AppendFormat("ExplicitPrefix: {0}\r\n",
                TokenList.ToString(ExplicitPrefix, maxDataLength, false));
        }

        result.AppendFormat("MemberName: {0}\r\n", MemberName);

        if (TypeParameters != null)
        {
            result.AppendFormat("TypeParameters: <{0}>\r\n",
                TokenList.Join(',', TypeParameters)
                    .ToString(maxDataLength, false, false));
        }

        if (BaseTypes != null)
        {
            TokenList separator = new TokenList();
            separator.Append(new Token(','));
            separator.Append(new Token(TokenType.WhiteSpace, " "));
            result.AppendFormat("BaseTypes: {0}\r\n",
                TokenList.JoinWithSeparator(separator, BaseTypes)
                    .ToString(maxDataLength, false, false));
        }

        if (BaseClassTopic != null)
            result.AppendFormat("BaseClassTopic: {0}\r\n", BaseClassTopic);

        if (Parameters != null)
        {
            StringBuilder data = new StringBuilder(200);
            foreach (Parameter parameter in Parameters)
            {
                if (data.Length == 0)
                    data.Append(parameter.ToString());
                else
                    data.AppendFormat(", {0}", parameter);
                if (data.Length > maxDataLength)
                    break;
            }
            result.Append("Parameters: ");
            if (data.Length > maxDataLength)
            {
                result.AppendFormat("{0}...",
                    data.ToString().Substring(0, maxDataLength - data.Length));
            }
            else
                result.Append(data.ToString());
            result.Append("\r\n");
        }

        if (Constraints != null)
        {
            result.AppendFormat("Constraints: {0}\r\n",
                TokenList.ToString(Constraints, maxDataLength, false));
        }

        if (GetAccessor != null)
            result.AppendFormat("GetAccessor: {0}\r\n", GetAccessor);

        if (SetAccessor != null)
            result.AppendFormat("SetAccessor: {0}\r\n", SetAccessor);

        if (EnumValueNamesArray != null)
        {
            result.AppendFormat("EnumValueNames: {0}\r\n",
                SourceFile.Ellipsis(String.Join(
                    ", ", EnumValueNamesArray), maxDataLength));
        }

        result.AppendFormat("Xml: {0}\r\n", SourceFile.Ellipsis(Xml,
            maxDataLength));

#if false
        result.Append(UsingContext.Dump());
#endif

        return result.ToString();
    }
#endif

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
Topic Constructor

Initializes an instance of this class.

Parameters

sourceFile

The source file containing this topic; null for a TopicKind.NamespaceTopic.

    internal Topic(SourceFile sourceFile)
    {
        m_sourceFile = sourceFile;
    }

    
Topic.AddChildTopic Method

Adds a given topic to ChildTopics.

Parameters

childTopic

The topic to add.

    internal void AddChildTopic(Topic childTopic)
    {
        if (m_childTopics == null)
            m_childTopics = new List<Topic>(20);
        m_childTopics.Add(childTopic);
    }

    
Topic.MemberwiseClone Method

Creates a shallow copy of the current Topic.

    internal new Topic MemberwiseClone()
    {
        return (Topic) base.MemberwiseClone();
    }

    
Topic.PrevalidateXmlComment Method

Performs a quick validation pass through the contents of the Xml property to check for basic structural problems such as an unknown top-level XML section type. Does not perform full validation of the documentation XML.

Exceptions
Exception type Condition
XmlException

An error is discovered in the documentation XML.

    internal void PrevalidateXmlComment()
    {
        foreach (XmlCommentSection section in XmlCommentSections)
        {
            using (XmlReader xmlReader = section.GetXmlReader())
            {
                while (xmlReader.Read())
                    ;
            }

        }
    }

    
Topic.NewParsingException Method (string, params object[])

Constructs and returns a new ParsingException referring to the current source file and the line number of the XML comment of this topic.

Parameters

format

A formatting string for an error message to include with the exception.

args

Formatting arguments for the error message.

    internal ParsingException NewParsingException(
        string format, params object[] args)
    {
        return new ParsingException(SourceFile.SourceFileAbsolutePath,
            FirstXmlComment.GetLineNumber(), format, args);
    }

    
Topic.NewParsingException Method (XmlReader, string, params object[])

Constructs and returns a new ParsingException referring to the source file of this topic and the line number of a given XmlReader.

Parameters

xmlReader

The XmlReader to get the line number of (to include in the exception text).

format

A formatting string for an error message to include with the exception.

args

Formatting arguments for the error message.

    internal ParsingException NewParsingException(
        XmlReader xmlReader, string format, params object[] args)
    {
        return new ParsingException(SourceFile.SourceFileAbsolutePath,
            ((IXmlLineInfo) xmlReader).LineNumber, format, args);
    }

    
Topic.MakeValidFileName Method

Creates a file name from a given string. For example, "A B" is converted to "A$20B".

Parameters

name

The string to convert to a file name.

    internal static string MakeValidFileName(string name)
    {
        name = name.Replace(SourceFile.LAngle, SourceFile.LSquare)
                   .Replace(SourceFile.RAngle, SourceFile.RSquare);
        return s_nonFileNameCharRegex.Replace(name, delegate(Match match)
        {
            Debug.Assert(match.Value.Length == 1);
            char ch = match.Value[0];
            if (ch < 0x100)
            {
                // replace ASCII characters with "$xx" (2-byte hex value)
                return String.Format("${0:X2}", (int) ch);
            }
            else
            {
                // replace non-ASCII Unicode characters with "$uXXXX" (4-byte
                // hex value)
                return String.Format("$u{0:X4}", (int) ch);
            }
        });
    }

    //////////////////////////////////////////////////////////////////////////
    // Private Methods
    //

    
Topic.CopyTypeName Method

Assuming this topic is a type topic, this method copies the type name represented by this topic, including ancestor types but not including the namespace, to a given token list. For example, if this topic is nested class "Ghi" within class "Def" within namespace "Abc", this method appends "Def.Ghi" to the given token list.

Parameters

tokenList

The TokenList to append to.

Return Value

true if anything was written to tokenList, false if not.

    public bool CopyTypeName(TokenList tokenList)
    {
        // do nothing if this isn't a type topic
        if (TopicKind == TopicKind.NamespaceTopic)
            return false;

        // recurse to add the ancesor types to <tokenList>
        if (ParentTopic != null)
        {
            if (ParentTopic.CopyTypeName(tokenList))
                tokenList.Append(new Token('.'));
        }

        // add the member name to <tokenList>
        tokenList.Append(new Token(TokenType.Word, MemberName));

        // add type parameters, if any
        if (TypeParameters != null)
        {
            tokenList.Append(new Token(SourceFile.LAngle));
            bool first = true;
            foreach (TokenList typeParameter in TypeParameters)
            {
                if (first)
                    first = false;
                else
                    tokenList.Append(new Token(','));
                tokenList.AppendCopy(typeParameter);
            }
            tokenList.Append(new Token(SourceFile.RAngle));
        }

        return true;
    }

    
Topic.ConstructQualifiedMemberName Method

Constructs the member name, with or without the namespace name (if any) and parent type name (if any) prepended.

Parameters

result

Where to write the result.

includeNamespace

true to include the parent namespace name in the result.

includeParentType

true to include the parent type name in the result.

includeExplicitPrefix

true to include the Topic.ExplicitPrefix in the result.

    void ConstructQualifiedMemberName(TokenList result, bool includeNamespace,
        bool includeParentType, bool includeExplicitPrefix)
    {
        if ((m_namespaceName != null) && includeNamespace)
        {
            foreach (Token token in m_namespaceName)
                result.Append(token.Clone());
        }
        if (includeParentType)
        {
            TokenList parentTypeName = ParentTypeName;
            if (parentTypeName != null)
            {
                if (!result.IsEmpty)
                    result.Append(new Token('.'));
                foreach (Token token in parentTypeName)
                    result.Append(token.Clone());
            }
        }
        if (m_memberName != null)
        {
            if (!result.IsEmpty)
                result.Append(new Token('.'));
            if (includeExplicitPrefix && (ExplicitPrefix != null))
                result.AppendCopy(ExplicitPrefix);
            result.Append(new Token(TokenType.Word, m_memberName));
        }
    }

    
Topic.GetTitle Method

Returns a title for this topic, based on a given member name. Type parameters and regular parameters are included if this is an overload topic (i.e. a topic for which there are other topics with the same BaseName).

Parameters

memberName

The member name to use in the title. This should be either QualifiedMemberName (for a long title) or QualifiedMemberNameWithoutNamespace (for a shorter title).

includeTopicKind

true to include the topic kind (e.g. "Method"), false if not.

    string GetTitle(string memberName, bool includeTopicKind)
    {
        StringBuilder result = new StringBuilder(200);
        result.Append(memberName);
        if ((TypeParameters != null) && (OverloadListTopic != null))
        {
            result.AppendFormat("<{0}>", TokenList.Join(',', TypeParameters)
                .ToString(int.MaxValue, false, false));
        }
        if (includeTopicKind)
        {
            if (TopicKind == TopicKind.MethodTopic)
            {
                if (MethodKind == MethodKind.Constructor)
                    result.AppendFormat(" {0}", Resources.Constructor);
                else
                if (MethodKind == MethodKind.Destructor)
                    result.AppendFormat(" {0}", Resources.Destructor);
                else
                    result.AppendFormat(" {0}", TopicKindTitle);
            }
            else
                result.AppendFormat(" {0}", TopicKindTitle);
        }
        if ((Parameters != null) && (OverloadListTopic != null))
        {
            result.Append(" (");
            bool firstParameter = true;
            foreach (Parameter parameter in Parameters)
            {
                if (firstParameter)
                    firstParameter = false;
                else
                    result.Append(", ");
                string kind = parameter.CSharpKind;
                if (kind != null)
                    result.AppendFormat("{0} ", kind);
                result.Append(parameter.ParameterType.ToString());
            }
            result.Append(")");
        }
        return result.ToString();
    }

    
Topic.GetOverloadingSignature Method

Returns a string that can be used to compare the member documented by this topic with another member to see if one overrides the other. Returns null if the member is not overloadable (e.g. a property, method, or event, excluding constructors and destructors).

Remarks

As described in sections 3.6 and 10.6.3 of the C# Language Specification 1.2 and section 20.6.1 of the C# Language Specification 2.0, the following are included in the returned signature:

  • the member name;
  • the number of type paramters;
  • the type and kind (value, reference or output) of each of the regular parameters.

A limitation of CodeDoc is that two parameter types are considered equivalent for the purpose of overloading if they are spelled identically. So, for example, Foo(string), Foo(String), and Foo(System.String) are all considered to be different signatures. To work around this limitation, use consistent spelling for method type names.

Another limitation of CodeDoc is that the names of type parameters are also included in the returned string. So, for example, if a method is overridden by a second method and the second method uses different type parameter names, it will be considered to be a new method rather than an override. To work around this limitation, use consistent naming for method type parameters.

    string GetOverloadingSignature()
    {
        // return null if this topic isn't an overloadable member
        if (TopicKind == TopicKind.PropertyTopic)
        {
            // all properties are overloadable
        }
        else
        if (TopicKind == TopicKind.MethodTopic)
        {
            // methods are overloadable except constructors and destructors
            if ((MethodKind == MethodKind.Constructor) ||
                (MethodKind == MethodKind.Destructor))
                return null;
        }
        else
        if (TopicKind == TopicKind.EventTopic)
        {
            // all events are overloadable
        }
        else
            return null; // not overloadable

        // the return value will be accumulated into <result>
        StringBuilder result = new StringBuilder(500);

        // append the member name
        if (MemberName != null)
            result.Append(MemberName);

        // append type parameters, if any
        if (TypeParameters != null)
        {
            result.AppendFormat("<{0}>",
                TokenList.Join(',', TypeParameters)
                    .ToString(int.MaxValue, false, false));
        }

        // append regular parameters, if any; don't include "params"
        // declarations
        if (Parameters != null)
        {
            result.Append(SourceFile.LParen);
            bool first = true;
            foreach (Parameter parameter in Parameters)
            {
                if (first)
                    first = false;
                else
                    result.Append(", ");
                if ((parameter.ParameterKind != ParameterKind.Unknown) &&
                    (parameter.ParameterKind != ParameterKind.Normal) &&
                    (parameter.ParameterKind != ParameterKind.Params))
                    result.AppendFormat("{0} ", parameter.CSharpKind);
                result.Append(parameter.ParameterType);
            }
            result.Append(SourceFile.RParen);
        }

        // done
        return result.ToString();
    }

    //////////////////////////////////////////////////////////////////////////
    // IComparable Implementation
    //

    int IComparable<Topic>.CompareTo(Topic other)
    {
        return String.Compare(LongSignature, other.LongSignature, true);
    }
}

NamespaceTopic Class

A TopicKind.NamespaceTopic documentation topic.

[DebuggerDisplay("{DebuggerDisplay}")]
public class NamespaceTopic : Topic
{
    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
NamespaceTopic.m_typeTopics Field

Holds the value of the TypeTopics property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    List<Topic> m_typeTopics = new List<Topic>(20);

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
NamespaceTopic.TypeTopics Property

Gets the list of type topics (i.e. TopicKind.ClassTopic, TopicKind.StructTopic, TopicKind.InterfaceTopic, TopicKind.DelegateTopic or TopicKind.EnumTopic) documented in this namespace by this documentation set.

    public IList<Topic> TypeTopics
    {
        [DebuggerStepThrough]
        get
        {
            return new ReadOnlyCollection<Topic>(m_typeTopics);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    
NamespaceTopic.SortTypeTopics Method
    public void SortTypeTopics()
    {
        if (m_typeTopics != null)
            m_typeTopics.Sort();
    }

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
NamespaceTopic Constructor

Initializes an instance of this class.

Parameters

namespaceName

The fully-qualified name of the namespace; for example, "Foo.Bar". This becomes the value of the Topic.MemberName property of the new NamespaceTopic.

    internal NamespaceTopic(string namespaceName)
        : base(null)
    {
        MemberName = namespaceName;
    }

    
NamespaceTopic.AddTypeTopic Method

Adds a topic to the TypeTopics collection, and sets the topic's Topic.IsTypeTopic property to true. This type must belong to this namespace, but it's permissible for the type to be nested within another type in this namespace.

Parameters

typeTopic

The topic to add.

    internal void AddTypeTopic(Topic typeTopic)
    {
        Debug.Assert(TokenList.ToString(typeTopic.NamespaceName)
            == MemberName);
        m_typeTopics.Add(typeTopic);
        typeTopic.IsTypeTopic = true;
    }
}

OverloadListTopic Class

A documentation topic that lists multiple versions, or "overloads", of topics that all have the same Topic.BaseName property value, i.e. the same Topic.QualifiedMemberName and the same TopicKind.

Remarks

An overload list topic is a topic you can link to (from references within CodeDoc-generated documentation or external documentation) when you don't know the type parameters or regular parameters of one or more components of the fully-qualified path of the target topic. For example, if you want to link to method "Bar" in class "Foo" but there are two "Bar" methods (with different parameter signatures), the "Foo.Bar method" overload list topic will list both methods and provide links to them. (If there was only one "Bar" method, then the link to "Foo.Bar method" would link directly to that topic. Overload list topics are only generated when there are multiple overloads with a single Topic.QualifiedMemberName and TopicKind.)

Usually, an overload list topic contains overload topics that belong to the same parent type (if any). Example:

C#
Foo.Bar(int)
Foo.Bar(int, bool)
However, it's possible for a single overload list topic to contain overload topics that refer to different types. Example:
C#
Foo<T>.Bar
Foo<T,U>.Bar
Or, even a combination of the two:
C#
Foo<T>.Bar
Foo<T,U>.Bar(int)
Foo<T,U>.Bar(int, bool)
Also, note that an overload topic can refer to types. Example:
C#
Foo<T>
Foo<T,U>

[DebuggerDisplay("{DebuggerDisplay}")]
public class OverloadListTopic : Topic
{
    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
OverloadListTopic.m_overloadTopics Field

Holds the value of the OverloadTopics property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    List<Topic> m_overloadTopics = new List<Topic>();

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
OverloadListTopic.OverloadTopics Property

Gets the list of overload topics, i.e. the topics that this OverloadListTopic collects together.

    public IList<Topic> OverloadTopics
    {
        [DebuggerStepThrough]
        get
        {
            return new ReadOnlyCollection<Topic>(m_overloadTopics);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    
OverloadListTopic.SortOverloadTopics Method
    public void SortOverloadTopics()
    {
        if (m_overloadTopics != null)
            m_overloadTopics.Sort();
    }

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
OverloadListTopic Constructor

Initializes an instance of this class.

    internal OverloadListTopic()
        : base(null)
    {
    }

    
OverloadListTopic.AddOverloadTopic Method

Adds a topic to the OverloadTopics collection.

Parameters

overloadTopic

The topic to add.

    internal void AddOverloadTopic(Topic overloadTopic)
    {
        Debug.Assert(overloadTopic.TopicKind == TopicKind);
        Debug.Assert(overloadTopic.NamespaceName == NamespaceName);
        Debug.Assert(overloadTopic.ParentTypeName == ParentTypeName);
        Debug.Assert(overloadTopic.MemberName == MemberName);
        m_overloadTopics.Add(overloadTopic);
    }
}

TopicKind Enumeration

Which kind of topic a Topic is.

Members
Name Description
ClassTopic

Topic is a class declaration.

DelegateTopic

Topic is a delegate declaration.

EnumTopic

Topic is a enum declaration.

EnumValueTopic

Topic is a enum value declaration, i.e. a value within an enum declaration.

EventTopic

Topic is a event declaration.

FieldTopic

Topic is a field declaration.

InterfaceTopic

Topic is a interface declaration.

MethodTopic

Topic is a method declaration.

NamespaceTopic

Topic is a namespace declaration.

PropertyTopic

Topic is a property declaration.

StructTopic

Topic is a struct declaration.

UnknownTopic

The topic kind is not yet known.

public enum TopicKind
{
    
TopicKind.UnknownTopic Enumeration Value

The topic kind is not yet known.

    UnknownTopic,

    
TopicKind.NamespaceTopic Enumeration Value

Topic is a namespace declaration.

    NamespaceTopic,

    
TopicKind.ClassTopic Enumeration Value

Topic is a class declaration.

    ClassTopic,

    
TopicKind.StructTopic Enumeration Value

Topic is a struct declaration.

    StructTopic,

    
TopicKind.InterfaceTopic Enumeration Value

Topic is a interface declaration.

    InterfaceTopic,

    
TopicKind.EventTopic Enumeration Value

Topic is a event declaration.

    EventTopic,

    
TopicKind.DelegateTopic Enumeration Value

Topic is a delegate declaration.

    DelegateTopic,

    
TopicKind.EnumTopic Enumeration Value

Topic is a enum declaration.

    EnumTopic,

    
TopicKind.EnumValueTopic Enumeration Value

Topic is a enum value declaration, i.e. a value within an enum declaration.

    EnumValueTopic,

    
TopicKind.MethodTopic Enumeration Value

Topic is a method declaration.

    MethodTopic,

    
TopicKind.PropertyTopic Enumeration Value

Topic is a property declaration.

    PropertyTopic,

    
TopicKind.FieldTopic Enumeration Value

Topic is a field declaration.

    FieldTopic,
}

MethodKind Enumeration

Which kind of method (if any) a Topic is.

Members
Name Description
Constructor

Method is a constructor.

Destructor

Method is a destructor.

Normal

Method is a normal method (not a constructor, destructor, or operator).

NotAMethod

Not a method. operator).

Operator

Method is an operator.

public enum MethodKind
{
    
MethodKind.NotAMethod Enumeration Value

Not a method. operator).

    NotAMethod = 0,

    
MethodKind.Normal Enumeration Value

Method is a normal method (not a constructor, destructor, or operator).

    Normal,

    
MethodKind.Constructor Enumeration Value

Method is a constructor.

    Constructor,

    
MethodKind.Destructor Enumeration Value

Method is a destructor.

    Destructor,

    
MethodKind.Operator Enumeration Value

Method is an operator.

    Operator,
}

PropertyKind Enumeration

Which kind of property (if any) a Topic is.

Members
Name Description
Indexer

Property is an indexer.

Normal

Property is a normal property (not an indexer).

NotAProperty

Not a property.

public enum PropertyKind
{
    
PropertyKind.NotAProperty Enumeration Value

Not a property.

    NotAProperty = 0,

    
PropertyKind.Normal Enumeration Value

Property is a normal property (not an indexer).

    Normal,

    
PropertyKind.Indexer Enumeration Value

Property is an indexer.

    Indexer,
}

Parameter Class

A parameter within a method or indexer declaration.

[DebuggerDisplay("{DebuggerDisplay}")]
public class Parameter
{
    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
Parameter.m_parameterKind Field

Holds the value of the ParameterKind property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    ParameterKind m_parameterKind;

    
Parameter.m_parameterType Field

Holds the value of the ParameterType property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList m_parameterType;

    
Parameter.m_parameterName Field

Holds the value of the ParameterName property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_parameterName;

    //////////////////////////////////////////////////////////////////////////
    // Private Properties
    //

#if DEBUG
    /// <summary>
    /// Gets a string displayed in the debugger.
    /// </summary>
    public string DebuggerDisplay
    {
        get
        {
            return ToString();
        }
    }
#endif

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
Parameter.ParameterKind Property

Gets which kind of parameter this is: out, ref, etc.

    public ParameterKind ParameterKind
    {
        [DebuggerStepThrough]
        get
        {
            return m_parameterKind;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_parameterKind = value;
        }
    }

    
Parameter.ParameterType Property

Gets the type of this parameter.

    public TokenList ParameterType
    {
        [DebuggerStepThrough]
        get
        {
            return m_parameterType;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_parameterType = value;
        }
    }

    
Parameter.ParameterName Property

Gets the name of this parameter.

    public string ParameterName
    {
        [DebuggerStepThrough]
        get
        {
            return m_parameterName;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_parameterName = value;
        }
    }

    
Parameter.CSharpKind Property

Gets the C# keyword equivalent of the ParameterKind value: "out", "ref", etc. Returns null for ParameterKind.Normal and ParameterKind.Unknown.

    public string CSharpKind
    {
        get
        {
            switch (m_parameterKind)
            {
            case ParameterKind.Out:
                return "out";
            case ParameterKind.Ref:
                return "ref";
            case ParameterKind.Params:
                return "params";
            default:
                return null;
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    
Parameter.ToString Method

Returns a string representation of the parameter.

    public override string ToString()
    {
        StringBuilder result = new StringBuilder(200);
        string kind = CSharpKind;
        if (kind != null)
            result.AppendFormat("{0} ", kind);
        result.Append(ParameterType.ToString());
        result.Append(' ');
        result.Append(ParameterName);
        return result.ToString();
    }

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
Parameter Constructor

Initializes an instance of this class.

    internal Parameter()
    {
    }
}

ParameterKind Enumeration

Which kind of parameter a Parameter is.

Members
Name Description
Normal

Parameter is input-only (i.e. passed by value).

Out

Parameter is output-only.

Params

Parameter is a "params" parameter (i.e. variable-length argument list).

Ref

Parameter is input/output (i.e. passed by reference).

Unknown

The parameter kind is not yet known.

public enum ParameterKind
{
    
ParameterKind.Unknown Enumeration Value

The parameter kind is not yet known.

    Unknown = 0,

    
ParameterKind.Normal Enumeration Value

Parameter is input-only (i.e. passed by value).

    Normal,

    
ParameterKind.Out Enumeration Value

Parameter is output-only.

    Out,

    
ParameterKind.Ref Enumeration Value

Parameter is input/output (i.e. passed by reference).

    Ref,

    
ParameterKind.Params Enumeration Value

Parameter is a "params" parameter (i.e. variable-length argument list).

    Params,
}

Accessor Class

A accessor within a method or indexer declaration.

[DebuggerDisplay("{DebuggerDisplay}")]
public class Accessor
{
    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
Accessor.m_accessorKind Field

Holds the value of the AccessorKind property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    AccessorKind m_accessorKind;

    
Accessor.m_accessorModifiers Field

Holds the value of the AccessorModifiers property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    TokenList m_accessorModifiers;

    //////////////////////////////////////////////////////////////////////////
    // Private Properties
    //

#if DEBUG
    /// <summary>
    /// Gets a string displayed in the debugger.
    /// </summary>
    public string DebuggerDisplay
    {
        get
        {
            return ToString();
        }
    }
#endif

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
Accessor.AccessorKind Property

Which kind of accessor this is.

    public AccessorKind AccessorKind
    {
        [DebuggerStepThrough]
        get
        {
            return m_accessorKind;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_accessorKind = value;
        }
    }

    
Accessor.AccessorModifiers Property

The modifiers of this accessor (e.g. "internal").

    public TokenList AccessorModifiers
    {
        [DebuggerStepThrough]
        get
        {
            return m_accessorModifiers;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_accessorModifiers = value;
        }
    }

    
Accessor.HasModifier Method

Returns true if this accessor has one of a given set of modifiers (such as "public"), false if not.

Parameters

modifiers

The modifiers to search for. Matching is performed in a case-sensitive manner.

    public bool HasModifier(params string[] modifiers)
    {
        if (m_accessorModifiers == null)
            return false;
        foreach (Token token in m_accessorModifiers)
        {
            foreach (string modifier in modifiers)
            {
                if (token.IsWordOrReservedWord(modifier))
                    return true;
            }
        }
        return false;
    }

    
Accessor.IsExternallyAccessible Property

Returns true if this accessor is accessible outside of this program or library -- assuming that the member associated with this accessor is similarly accessible.

    public bool IsExternallyAccessible
    {
        get
        {
            // if no modifiers are specified, default to public access
            if (AccessorModifiers == null)
                return true;

            // otherwise, the accessor is only externally accessible if its
            // modifiers include "protected" -- see section 25.1.1 of the C#
            // Language Specification 2.0
            return HasModifier("protected");
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    
Accessor.ToString Method

Returns a string representation of the accessor.

    public override string ToString()
    {
        StringBuilder result = new StringBuilder(200);
        if (AccessorModifiers != null)
            result.Append(AccessorModifiers.ToString());
        if (result.Length != 0)
            result.Append(' ');
        if (AccessorKind == AccessorKind.Get)
            result.Append("get");
        else
        if (AccessorKind == AccessorKind.Set)
            result.Append("set");
        else
            Debug.Assert(false);
        return result.ToString();
    }

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
Accessor Constructor

Initializes an instance of this class.

    internal Accessor()
    {
    }
}

AccessorKind Enumeration

Which kind of accessor a Accessor is.

Members
Name Description
Get

Accessor is a "get" accessor.

Set

Accessor is a "set" accessor.

Unknown

The accessor kind is not yet known.

public enum AccessorKind
{
    
AccessorKind.Unknown Enumeration Value

The accessor kind is not yet known.

    Unknown = 0,

    
AccessorKind.Get Enumeration Value

Accessor is a "get" accessor.

    Get,

    
AccessorKind.Set Enumeration Value

Accessor is a "set" accessor.

    Set,
}

XmlCommentSection Class

Represents to a top-level section (for example, "<summary>" or "<param>") of an XML comment block.

[DebuggerDisplay("XmlCommentSection: {SectionKind}")]
public class XmlCommentSection
{
    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
XmlCommentSection.s_sectionKindDictionary Field

Maps an XML comment section name (e.g. "summary") to a XmlCommentSectionKind enumeration value.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    static Dictionary<string, XmlCommentSectionKind> s_sectionKindDictionary =
        InitializeSectionKindDictionary();

    
XmlCommentSection.m_topic Field

Holds the value of the Topic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Topic m_topic;

    
XmlCommentSection.m_sectionKind Field

Holds the value of the SectionKind property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    XmlCommentSectionKind m_sectionKind;

    
XmlCommentSection.m_sectionName Field

Holds the value of the SectionName property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_sectionName;

    
XmlCommentSection.m_nameAttribute Field

Holds the value of the NameAttribute property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_nameAttribute;

    
XmlCommentSection.m_crefAttribute Field

Holds the value of the CrefAttribute property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_crefAttribute;

    
XmlCommentSection.m_hrefAttribute Field

Holds the value of the HrefAttribute property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_hrefAttribute;

    
XmlCommentSection.m_html Field

Holds the value of the Html property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_html;

    
XmlCommentSection.m_enumerating Field

Holds the value of the Enumerating property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    bool m_enumerating;

    
XmlCommentSection.m_lineNumber Field

Holds the value of the LineNumber property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    int m_lineNumber;

    
XmlCommentSection.m_referencedTopic Field

Holds the value of the ReferencedTopic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Topic m_referencedTopic;

    
XmlCommentSection.m_xmlReader Field

Reads through Topic.Xml.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    XmlReader m_xmlReader;

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
XmlCommentSection.Topic Property

Gets the Topic that contains the XML that contains this XmlCommentSection.

    public Topic Topic
    {
        [DebuggerStepThrough]
        get
        {
            return m_topic;
        }
    }

    
XmlCommentSection.SectionKind Property

Gets which kind of XML comment section this is.

    public XmlCommentSectionKind SectionKind
    {
        [DebuggerStepThrough]
        get
        {
            return m_sectionKind;
        }
    }

    
XmlCommentSection.SectionName Property

Gets the name of this section; for example, "summary". This name corresponds to SectionKind.

    public string SectionName
    {
        [DebuggerStepThrough]
        get
        {
            return m_sectionName;
        }
    }

    
XmlCommentSection.NameAttribute Property

Sets or gets the value of the "name" XML attribute of this section -- null if there is no "name" attribute.

    public string NameAttribute
    {
        [DebuggerStepThrough]
        get
        {
            return m_nameAttribute;
        }
        [DebuggerStepThrough]
        set
        {
            m_nameAttribute = value;
        }
    }

    
XmlCommentSection.CrefAttribute Property

Sets or gets the value of the "cref" XML attribute of this section -- null if there is no "cref" attribute.

    public string CrefAttribute
    {
        [DebuggerStepThrough]
        get
        {
            return m_crefAttribute;
        }
        [DebuggerStepThrough]
        set
        {
            m_crefAttribute = value;
        }
    }

    
XmlCommentSection.HrefAttribute Property

Sets or gets the value of the "href" XML attribute of this section -- null if there is no "href" attribute.

    public string HrefAttribute
    {
        [DebuggerStepThrough]
        get
        {
            return m_hrefAttribute;
        }
        [DebuggerStepThrough]
        set
        {
            m_hrefAttribute = value;
        }
    }

    
XmlCommentSection.Html Property

The HTML representation of this section.

    public string Html
    {
        [DebuggerStepThrough]
        get
        {
            return m_html;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_html = value;
        }
    }

    
XmlCommentSection.Enumerating Property

true if this XmlCommentSection is participating in an enumeration through all top-level sections (e.g. "<summary>" or "<param>") of an XML comment block.

    public bool Enumerating
    {
        [DebuggerStepThrough]
        get
        {
            return m_enumerating;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_enumerating = value;
        }
    }

    
XmlCommentSection.LineNumber Property

Sets or gets the line number of this XmlCommentSection within the source file that contains it.

    public int LineNumber
    {
        [DebuggerStepThrough]
        get
        {
            return m_lineNumber;
        }
        [DebuggerStepThrough]
        set
        {
            m_lineNumber = value;
        }
    }

    
XmlCommentSection.ReferencedTopic Property

Sets or gets the topic referenced by this XmlCommentSection (for example, via the "cref" attribute); null if none.

    public Topic ReferencedTopic
    {
        [DebuggerStepThrough]
        get
        {
            return m_referencedTopic;
        }
        [DebuggerStepThrough]
        set
        {
            m_referencedTopic = value;
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    
XmlCommentSection.GetXmlReader Method

Returns an XmlReader instance that can be used to read this XML comment section.

Return Value

A new XmlReader instance set to ReadState.Initial. A call to the Read method positions the new XmlReader on the opening element of this XML section node; for example, "<summary>" node. Read will return false on the first call after the call that reads the end element (e.g. "</summary>"). If the XML section is an empty element (e.g. "<summary/>" -- XmlReader.IsEmptyElement returns true), then the first call to Read will return the element and the next call will return false.

Exceptions
Exception type Condition
InvalidOperationException

Enumerating is false before calling this method.

Remarks

Close must be called on the returned XmlReader before reading any further XmlCommentSection objects of this topic.

If Enumerating is false, GetXmlReader cannot be called.

    public XmlReader GetXmlReader()
    {
        if (m_xmlReader == null)
            throw new InvalidOperationException(Resources.NotEnumerating);
        return m_xmlReader.ReadSubtree();
    }

#if false
    /// <summary>
    /// Disconnects this <r>XmlCommentSection</r> object from the object that
    /// created it, so that this <r>XmlCommentSection</r> object can safely
    /// be added to a list.
    /// </summary>
    ///
    /// <remarks>
    /// Once <r>Disconnect</r> is called, <r>GetXmlReader</r> can no longer be
    /// called.
    /// </remarks>
    ///
    public void Disconnect()
    {
        m_xmlReader = null;
    }
#endif

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
XmlCommentSection Constructor

Initializes an instance of this class.

Parameters

topic

The Topic containing the XML being parsed by this XmlCommentSection instance.

xmlReader

An XmlReader positioned on a top-level XML element within an XML comment block.

Exceptions
Exception type Condition
ParsingException

An error is discovered in the documentation XML.

    internal XmlCommentSection(Topic topic, XmlReader xmlReader)
    {
        // note: <topic> may not be fully initialized -- use with caution
        m_topic = topic;
        m_xmlReader = xmlReader;
        Debug.Assert(xmlReader.NodeType == XmlNodeType.Element);
        m_sectionName = xmlReader.Name;
        if (!s_sectionKindDictionary.TryGetValue(m_sectionName,
            out m_sectionKind))
        {
            throw topic.NewParsingException(xmlReader,
                Resources.UnknownXmlCommentSection, m_sectionName);
        }
    }

    
XmlCommentSection.ReadToEnd Method

Advances XmlReader to the end element of this XML comment section (e.g. "</summary>").

    internal void ReadToEnd()
    {
        while (true)
        {
            if (((m_xmlReader.NodeType == XmlNodeType.EndElement) ||
                 m_xmlReader.IsEmptyElement) &&
                (m_xmlReader.Name == m_sectionName) &&
                (m_xmlReader.Depth == 0))
                break;
            if (!m_xmlReader.Read())
                break;
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Private Methods
    //

    
XmlCommentSection.InitializeSectionKindDictionary Method

Returns the initial value of s_sectionKindDictionary.

    static Dictionary<string, XmlCommentSectionKind>
        InitializeSectionKindDictionary()
    {
        // could have used Enum.Parse(), but that's a bit hacky and slow
        Dictionary<string, XmlCommentSectionKind> dictionary =
            new Dictionary<string, XmlCommentSectionKind>();
        dictionary.Add("summary", XmlCommentSectionKind.Summary);
        dictionary.Add("param", XmlCommentSectionKind.Param);
        dictionary.Add("typeparam", XmlCommentSectionKind.TypeParam);
        dictionary.Add("returns", XmlCommentSectionKind.Returns);
        dictionary.Add("value", XmlCommentSectionKind.Value);
        dictionary.Add("remarks", XmlCommentSectionKind.Remarks);
        dictionary.Add("example", XmlCommentSectionKind.Example);
        dictionary.Add("exception", XmlCommentSectionKind.Exception);
        dictionary.Add("permission", XmlCommentSectionKind.Permission);
        dictionary.Add("seealso", XmlCommentSectionKind.SeeAlso);
        return dictionary;
    }
}

MemberInfo Class

Information about a topic that is listed in the "Members" section of another topic.

[DebuggerDisplay("MemberInfo: {Topic}")]
public class MemberInfo : IComparable<MemberInfo>
{
    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
MemberInfo.m_topic Field

Holds the value of the Topic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Topic m_topic;

    
MemberInfo.m_inheritedFromTopic Field

Holds the value of the InheritedFromTopic property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    Topic m_inheritedFromTopic;

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
MemberInfo.Topic Property

Gets the Topic of this member.

    public Topic Topic
    {
        [DebuggerStepThrough]
        get
        {
            return m_topic;
        }
    }

    
MemberInfo.InheritedFromTopic Property

Gets the Topic of the class that this member is inherited from or null if this member wasn't inherited (i.e. it is a direct member of the topic being enumerated).

    public Topic InheritedFromTopic
    {
        [DebuggerStepThrough]
        get
        {
            return m_inheritedFromTopic;
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
MemberInfo Constructor

Initializes an instance of this class.

Parameters

topic

The value to use for the Topic property.

inheritedFromTopic

The value to use for the InheritedFromTopic property.

    internal MemberInfo(Topic topic, Topic inheritedFromTopic)
    {
        m_topic = topic;
        m_inheritedFromTopic = inheritedFromTopic;
    }

    //////////////////////////////////////////////////////////////////////////
    // IComparable<T> Implementation
    //

    int IComparable<MemberInfo>.CompareTo(MemberInfo other)
    {
        return String.Compare(Topic.VeryShortTitleNoKind, other.Topic.VeryShortTitleNoKind, true);
    }
}

XmlCommentSectionKind Enumeration

Identifies a top-level section (for example, "<summary>" and "<param>") of an XML comment block.

Members
Name Description
Example

An <example> section in an XML comment block.

Exception

An <exception> section in an XML comment block.

Length

Value equal to the number of enumeration members in XmlCommentSectionKind.

Param

A <param> section in an XML comment block.

Permission

A <permission> section in an XML comment block.

Remarks

A <remarks> section in an XML comment block.

Returns

A <returns> section in an XML comment block.

SeeAlso

A <permission> section in an XML comment block.

Summary

A <summary> section in an XML comment block.

TypeParam

A <typeparam> section in an XML comment block.

Value

A <value> section in an XML comment block.

public enum XmlCommentSectionKind
{
    
XmlCommentSectionKind.Summary Enumeration Value

A <summary> section in an XML comment block.

    Summary = 0,

    
XmlCommentSectionKind.Param Enumeration Value

A <param> section in an XML comment block.

    Param = 1,

    
XmlCommentSectionKind.TypeParam Enumeration Value

A <typeparam> section in an XML comment block.

    TypeParam = 2,

    
XmlCommentSectionKind.Returns Enumeration Value

A <returns> section in an XML comment block.

    Returns = 3,

    
XmlCommentSectionKind.Value Enumeration Value

A <value> section in an XML comment block.

    Value = 4,

    
XmlCommentSectionKind.Remarks Enumeration Value

A <remarks> section in an XML comment block.

    Remarks = 5,

    
XmlCommentSectionKind.Example Enumeration Value

An <example> section in an XML comment block.

    Example = 6,

    
XmlCommentSectionKind.Exception Enumeration Value

An <exception> section in an XML comment block.

    Exception = 7,

    
XmlCommentSectionKind.Permission Enumeration Value

A <permission> section in an XML comment block.

    Permission = 8,

    
XmlCommentSectionKind.SeeAlso Enumeration Value

A <permission> section in an XML comment block.

    SeeAlso = 9,

    /* if you update this list, update InitializeSectionKindDictionary() */

    
XmlCommentSectionKind.Length Enumeration Value

Value equal to the number of enumeration members in XmlCommentSectionKind.

    Length = 10/*must be equal to highest-numbered value plus one*/,
}

HtmlTextWriterDelegate Delegate

A delegate which writes to a given HtmlTextWriter.

Parameters

writer

The HtmlTextWriter to write to.

public delegate void HtmlTextWriterDelegate(HtmlTextWriter writer);

}