XML 문서 주석

C# 소스 파일에는 해당 파일에 정의된 형식에 대한 API 문서를 생성하는 구조적 주석이 있을 수 있습니다. C# 컴파일러는 주석과 API 시그니처를 나타내는 정형 데이터가 포함된 XML 파일을 생성합니다. 예를 들어 다른 도구는 해당 XML 출력을 처리하여 사용자가 읽을 수 있는 문서를 웹 페이지 또는 PDF 파일 형식으로 만들 수 있습니다.

이 프로세스는 코드에 API 문서를 추가할 경우 다음과 같은 많은 이점을 제공합니다.

  • C# 컴파일러가 C# 코드의 구조와 주석의 텍스트를 단일 XML 문서로 결합합니다.
  • C# 컴파일러가 주석이 관련 태그의 API 시그니처와 일치하는지 확인합니다.
  • XML 문서 파일을 처리하는 도구가 해당 도구와 관련된 XML 요소 및 특성을 정의할 수 있습니다.

Visual Studio와 같은 도구는 문서 주석에 사용되는 여러 일반적인 XML 요소에 대해 IntelliSense를 제공합니다.

이 문서에서는 다음과 같은 주제를 다룹니다.

  • 문서 주석 및 XML 파일 생성
  • C# 컴파일러 및 Visual Studio에서 유효성을 검사하는 태그
  • 생성된 XML 파일의 형식

XML 문서 출력 만들기

삼중 슬래시로 나타낸 특수 주석 필드를 작성하여 코드에 대한 문서를 만듭니다. 주석 필드에는 주석 다음에 나오는 코드 블록을 설명하는 XML 요소가 포함됩니다. 예를 들어:

/// <summary>
///  This class performs an important function.
/// </summary>
public class MyClass {}

GenerateDocumentationFile 또는 DocumentationFile 옵션을 설정하면 컴파일러가 소스 코드에서 XML 태그가 있는 모든 주석 필드를 찾고 해당 주석에서 XML 문서 파일을 만듭니다. 이 옵션을 사용하도록 설정하면 컴파일러가 XML 문서 주석 없이 프로젝트에 선언된 공개적으로 표시되는 모든 멤버에 대해 CS1591 경고를 생성합니다.

XML 주석 형식

XML 문서 주석을 사용하려면 문서 주석이 시작하고 끝나는 위치를 나타내는 구분 기호가 필요합니다. XML 문서 태그에 다음과 같은 구분 기호를 사용할 수 있습니다.

  • /// 한 줄 구분 기호: 문서 예제와 C# 프로젝트 템플릿에서는 이 형식을 사용합니다. 구분 기호 뒤에 공백이 있는 경우 해당 공백은 XML 출력에 포함되지 않습니다.

    참고

    Visual Studio는 사용자가 코드 편집기에서 /// 구분 기호를 입력한 후 <summary></summary> 태그를 자동으로 삽입하고 커서를 이러한 태그 내에 배치합니다. 이 기능은 옵션 대화 상자에서 켜거나 끌 수 있습니다.

  • /** */ 여러 줄 구분 기호: /** */ 구분 기호는 다음과 같은 서식 지정 규칙을 포함합니다.
    • /** 구분 기호가 포함된 줄에서 줄의 나머지 부분이 공백인 경우 해당 줄은 주석으로 처리되지 않습니다. /** 구분 기호 다음의 첫 번째 문자가 공백인 경우 해당 공백 문자는 무시되고 줄의 나머지 부분이 처리됩니다. 그러지 않으면 /** 구분 기호 다음 줄의 전체 텍스트가 주석의 일부로 처리됩니다.

    • */ 구분 기호가 포함된 줄에서 */ 구분 기호까지 공백만 있으면 해당 줄은 무시됩니다. 그렇지 않으면 */ 구분 기호 이전 줄의 텍스트가 주석의 일부로 처리됩니다.

    • /** 구분 기호로 시작하는 줄 다음 줄에 대해 컴파일러는 각 줄의 시작 부분에서 일반적인 패턴을 찾습니다. 패턴은 선택적 공백과 별표(*)로 구성되고 그다음에 더 많은 선택적 공백이 올 수 있습니다. 컴파일러가 /** 구분 기호로 시작하거나 */ 구분 기호로 끝나지 않는 각 줄의 시작 부분에서 일반적인 패턴을 찾으면 각 줄의 해당 패턴을 무시합니다.

    • 다음 주석에서 유일하게 처리되는 부분은 <summary>로 시작하는 줄입니다. 세 가지 태그 서식이 동일한 주석을 생성합니다.

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • 컴파일러는 두 번째 및 세 번째 줄의 시작 부분에서 " * "의 일반적인 패턴을 식별합니다. 이 패턴은 출력에 포함되지 않습니다.

      /**
      * <summary>
      * text </summary>*/
      
    • 다음 주석에서는 세 번째 줄의 두 번째 문자가 별표가 아니므로 컴파일러가 일반적인 패턴을 찾을 수 없습니다. 두 번째 및 세 번째 줄의 모든 텍스트가 주석의 일부로 처리됩니다.

      /**
      * <summary>
         text </summary>
      */
      
    • 다음 주석에서는 두 가지로 이유로 컴파일러가 패턴을 찾을 수 없습니다. 첫째, 별표 앞의 공백 수가 일치하지 않습니다. 둘째, 다섯 번째 줄이 공백과 일치하지 않는 탭으로 시작합니다. 두 번째 줄부터 다섯 번째 줄까지 모든 텍스트가 주석의 일부로 처리됩니다.

      /**
        * <summary>
        * text
      *  text2
       	*  </summary>
      */
      

XML 요소를 참조하려면(예를 들어, 함수가 XML 문서 주석에서 설명하려는 특정 XML 요소를 처리하는 경우) 표준 인용 메커니즘(&lt;&gt;)을 사용할 수 있습니다. 코드 참조(cref) 요소에서 제네릭 식별자를 참조하려면 이스케이프 문자(예: cref="List&lt;T&gt;") 또는 괄호(cref="List{T}")를 사용할 수 있습니다. 특별한 경우로, 컴파일러는 제네릭 식별자를 참조할 때 문서 주석을 더 쉽게 작성할 수 있도록 괄호를 꺾쇠 괄호로 구문 분석합니다.

참고

XML 문서 주석은 메타데이터가 아닙니다. 이러한 주석은 컴파일된 어셈블리에 포함되지 않으므로 리플렉션을 통해 액세스할 수 없습니다.

XML 문서 입력을 허용하는 도구

다음 도구는 XML 주석에서 출력을 만듭니다.

  • DocFX: DocFX는 현재 C#, Visual Basic, F#을 지원하는 .NET용 API 문서 생성기입니다. 또한 생성된 참조 문서를 사용자 지정할 수 있습니다. DocFX는 소스 코드 및 Markdown 파일에서 정적 HTML 웹 사이트를 빌드합니다. 또한 DocFX는 템플릿을 통해 웹 사이트의 레이아웃과 스타일을 유연하게 사용자 지정할 수 있게 해줍니다. 사용자 지정 템플릿을 만들 수도 있습니다.
  • Sandcastle: ‘Sandcastle 도구’는 개념 페이지와 API 참조 페이지를 모두 포함하는 관리형 클래스 라이브러리의 도움말 파일을 만듭니다. Sandcastle 도구는 명령줄 기반이며 GUI 프런트 엔드, 프로젝트 관리 기능 또는 자동화된 빌드 프로세스가 없습니다. Sandcastle Help File Builder는 자동화된 방식으로 도움말 파일을 빌드할 수 있는 독립 실행형 GUI 및 명령줄 기반 도구를 제공합니다. 전적으로 Visual Studio 내에서 도움말 프로젝트를 만들고 관리할 수 있도록 Visual Studio 통합 패키지도 사용할 수 있습니다.
  • Doxygen: Doxygen은 문서화된 소스 파일 집합에서 온라인 문서 브라우저(HTML) 또는 오프라인 참조 매뉴얼(LaTeX)을 생성합니다. RTF(MS Word), 포스트스크립트, 하이퍼링크된 PDF, 압축 HTML, DocBook, Unix man 페이지에서 출력을 생성하는 기능도 지원됩니다. 문서화되지 않은 소스 파일에서 코드 구조를 추출하도록 Doxygen을 구성할 수 있습니다.

ID 문자열

각 형식 또는 멤버는 출력 XML 파일의 요소에 저장됩니다. 이러한 각 요소에는 형식 또는 멤버를 식별하는 고유 ID 문자열이 있습니다. 이 ID 문자열은 연산자, 매개 변수, 반환 값, 제네릭 형식 매개 변수, ref, in, out 매개 변수를 고려해야 합니다. 이러한 잠재적 요소를 모두 인코딩하기 위해 컴파일러는 ID 문자열 생성에 대해 명확하게 정의된 규칙을 따릅니다. XML 파일을 처리하는 프로그램은 ID 문자열을 사용하여 문서가 적용되는 해당 .NET 메타데이터 또는 리플렉션 항목을 식별합니다.

컴파일러는 ID 문자열을 생성할 때 다음 규칙을 관찰합니다.

  • 문자열에 공백이 없음.

  • 문자열의 첫 부분이 뒤에 콜론이 붙은 한 글자를 사용해 멤버의 종류를 식별합니다. 사용되는 멤버 유형은 다음과 같습니다.

    문자 멤버 형식 참고
    N namespace 네임스페이스에 문서 주석을 추가할 수는 없지만, 지원되는 경우 문서 주석에 대한 cref 참조를 만들 수는 있습니다.
    T type 형식은 클래스, 인터페이스, 구조체, 열거형 또는 대리자입니다.
    F 필드(field)
    P 속성(property) 인덱서 또는 기타 인덱싱된 속성을 포함합니다.
    M 메서드 생성자 및 연산자와 같은 특수 메서드를 포함합니다.
    E event
    ! 오류 문자열 문자열의 나머지 부분은 오류에 대한 정보를 제공합니다. C# 컴파일러는 확인할 수 없는 링크에 대해 오류 정보를 생성합니다.
  • 문자열의 두 번째 부분은 네임스페이스의 루트부터 시작되는 항목의 정규화된 이름입니다. 항목의 이름과 바깥쪽 형식 및 네임스페이스는 마침표로 구분됩니다. 항목 자체의 이름에 마침표가 있으면 이러한 요소를 구분하는 마침표가 해시 기호(‘#’)로 바뀝니다. 항목 이름에는 해시 기호가 직접적으로 포함되지 않는다고 가정합니다. 예를 들어 String 생성자의 정규화된 이름은 “System.String.#ctor”입니다.

  • 속성 및 메서드의 경우 괄호로 묶은 매개 변수 목록이 뒤에 나옵니다. 매개 변수가 없으면 괄호도 없습니다. 매개 변수는 쉼표로 구분됩니다. 각 매개 변수의 인코딩은 .NET 시그니처에서 인코딩되는 방법을 직접 따릅니다(다음 목록의 모든 대문자 요소의 정의는 Microsoft.VisualStudio.CorDebugInterop.CorElementType 참조).

    • 기본 형식. 일반 형식(ELEMENT_TYPE_CLASS 또는 ELEMENT_TYPE_VALUETYPE)은 형식의 정규화된 이름으로 표시됩니다.
    • 내장 형식(예: ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_STRING, ELEMENT_TYPE_TYPEDBYREF, ELEMENT_TYPE_VOID)은 해당하는 전체 형식의 정규화된 이름으로 표시됩니다. 예를 들어 System.Int32 또는 System.TypedReference입니다.
    • ELEMENT_TYPE_PTR 는 수정된 형식에 따라 '*'로 표시됩니다.
    • ELEMENT_TYPE_BYREF 는 수정된 형식에 따라 '@'로 표시됩니다.
    • ELEMENT_TYPE_CMOD_OPT는 수정된 형식 뒤에 ‘!’ 및 한정자 클래스의 정규화된 이름으로 표시됩니다.
    • ELEMENT_TYPE_SZARRAY는 배열의 요소 형식 뒤에 “[]”로 표시됩니다.
    • ELEMENT_TYPE_ARRAY 는 [ELEMENT_TYPE_ARRAY:size,size:size]로 표시됩니다. 여기서 쉼표 수는 순위 - 1이고 각 차원의 하한과 크기(알려진 경우)는 10진수로 표시됩니다. 하한이나 크기가 지정되지 않은 경우에는 생략됩니다. 특정 차원의 하한과 크기를 생략하면 ':'도 생략됩니다. 예를 들어 하한이 1이고 크기가 지정되지 않은 2차원 배열은 [1:,1:]로 표시됩니다.
  • 변환 연산자(op_Implicitop_Explicit)에 한해 메서드의 반환 값은 뒤에 반환 형식이 붙은 ~로 인코딩됩니다. 예: <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32">System.Decimal 클래스에 선언된 캐스팅 연산자 public static explicit operator int (decimal value);의 태그입니다.

  • 제네릭 형식의 경우에는 형식 이름 뒤에 억음 악센트 기호와 제네릭 형식 매개 변수의 수를 나타내는 숫자가 차례로 붙습니다. 예: <member name="T:SampleClass``2">public class SampleClass<T, U>로 정의된 형식의 태그입니다. 제네릭 형식을 매개 변수로 사용하는 메서드의 경우 제네릭 형식 매개 변수는 앞에 백틱이 있는 숫자로 지정됩니다(예: '0,'1). 각 숫자는 해당 형식의 제네릭 매개 변수에 대한 0부터 시작되는 배열 표기법을 나타냅니다.

    • ELEMENT_TYPE_PINNED는 수정된 형식 뒤에 ‘^’으로 표시됩니다. C# 컴파일러는 이 인코딩을 생성하지 않습니다.
    • ELEMENT_TYPE_CMOD_REQ 는 수정된 형식에 따라 '|'과 한정자 클래스의 정규화된 이름으로 표시됩니다. C# 컴파일러는 이 인코딩을 생성하지 않습니다.
    • ELEMENT_TYPE_GENERICARRAY는 배열의 요소 형식 뒤에 “[?]”로 표시됩니다. C# 컴파일러는 이 인코딩을 생성하지 않습니다.
    • ELEMENT_TYPE_FNPTR 는 반환 형식인 "=FUNC:type(ELEMENT_TYPE_FNPTR)" type 로 표현되고 type 는 메서드의 인수입니다. 인수가 없으면 괄호는 생략됩니다. C# 컴파일러는 이 인코딩을 생성하지 않습니다.
    • 다음 시그니처 구성 요소는 오버로드된 메서드를 구분하는 데 사용되지 않으므로 표시되지 않습니다.
      • 호출 규칙
      • 반환 형식
      • ELEMENT_TYPE_SENTINEL

다음 예제에서는 클래스와 해당 멤버의 ID 문자열이 생성되는 방식을 보여 줍니다.

namespace MyNamespace
{
    /// <summary>
    /// Enter description here for class X.
    /// ID string generated is "T:MyNamespace.MyClass".
    /// </summary>
    public unsafe class MyClass
    {
        /// <summary>
        /// Enter description here for the first constructor.
        /// ID string generated is "M:MyNamespace.MyClass.#ctor".
        /// </summary>
        public MyClass() { }

        /// <summary>
        /// Enter description here for the second constructor.
        /// ID string generated is "M:MyNamespace.MyClass.#ctor(System.Int32)".
        /// </summary>
        /// <param name="i">Describe parameter.</param>
        public MyClass(int i) { }

        /// <summary>
        /// Enter description here for field message.
        /// ID string generated is "F:MyNamespace.MyClass.message".
        /// </summary>
        public string? message;

        /// <summary>
        /// Enter description for constant PI.
        /// ID string generated is "F:MyNamespace.MyClass.PI".
        /// </summary>
        public const double PI = 3.14;

        /// <summary>
        /// Enter description for method func.
        /// ID string generated is "M:MyNamespace.MyClass.func".
        /// </summary>
        /// <returns>Describe return value.</returns>
        public int func() { return 1; }

        /// <summary>
        /// Enter description for method someMethod.
        /// ID string generated is "M:MyNamespace.MyClass.someMethod(System.String,System.Int32@,System.Void*)".
        /// </summary>
        /// <param name="str">Describe parameter.</param>
        /// <param name="num">Describe parameter.</param>
        /// <param name="ptr">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public int someMethod(string str, ref int nm, void* ptr) { return 1; }

        /// <summary>
        /// Enter description for method anotherMethod.
        /// ID string generated is "M:MyNamespace.MyClass.anotherMethod(System.Int16[],System.Int32[0:,0:])".
        /// </summary>
        /// <param name="array1">Describe parameter.</param>
        /// <param name="array">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public int anotherMethod(short[] array1, int[,] array) { return 0; }

        /// <summary>
        /// Enter description for operator.
        /// ID string generated is "M:MyNamespace.MyClass.op_Addition(MyNamespace.MyClass,MyNamespace.MyClass)".
        /// </summary>
        /// <param name="first">Describe parameter.</param>
        /// <param name="second">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public static MyClass operator +(MyClass first, MyClass second) { return first; }

        /// <summary>
        /// Enter description for property.
        /// ID string generated is "P:MyNamespace.MyClass.prop".
        /// </summary>
        public int prop { get { return 1; } set { } }

        /// <summary>
        /// Enter description for event.
        /// ID string generated is "E:MyNamespace.MyClass.OnHappened".
        /// </summary>
        public event Del? OnHappened;

        /// <summary>
        /// Enter description for index.
        /// ID string generated is "P:MyNamespace.MyClass.Item(System.String)".
        /// </summary>
        /// <param name="str">Describe parameter.</param>
        /// <returns></returns>
        public int this[string s] { get { return 1; } }

        /// <summary>
        /// Enter description for class Nested.
        /// ID string generated is "T:MyNamespace.MyClass.Nested".
        /// </summary>
        public class Nested { }

        /// <summary>
        /// Enter description for delegate.
        /// ID string generated is "T:MyNamespace.MyClass.Del".
        /// </summary>
        /// <param name="i">Describe parameter.</param>
        public delegate void Del(int i);

        /// <summary>
        /// Enter description for operator.
        /// ID string generated is "M:MyNamespace.MyClass.op_Explicit(MyNamespace.MyClass)~System.Int32".
        /// </summary>
        /// <param name="myParameter">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public static explicit operator int(MyClass myParameter) { return 1; }
    }
}

C# 언어 사양

자세한 내용은 문서 주석에 대한 C# 언어 사양 부록을 참조하세요.