【问题标题】:How to reference generic classes and methods in xml documentation如何在 xml 文档中引用泛型类和方法
【发布时间】:2009-02-10 12:50:38
【问题描述】:

在编写 xml 文档时,您可以使用<see cref="something">something</see>,这当然可以。但是如何引用具有泛型类型的类或方法呢?

public class FancyClass<T>
{
  public string FancyMethod<K>(T value) { return "something fancy"; }
}

如果我要在某处编写 xml 文档,我将如何引用花哨的类?如何引用FancyClass&lt;string&gt;?方法呢?

例如,在另一个类中,我想让用户知道我将返回一个FancyClass&lt;int&gt; 的实例。我怎么能为此做一个 see cref 呢?

【问题讨论】:

    标签: c# generics reference xml-documentation


    【解决方案1】:

    引用方法:

    /// <see cref="FancyClass{T}.FancyMethod{K}(T)"/> for more information.
    

    【讨论】:

    • 感谢您的回答! 上的 MSDN 页面实际上缺少它:msdn.microsoft.com/en-us/library/acd0tfbe.aspx
    • 我实际上相信它也可以在 VS2010 工具提示中工作,您需要指出通用参数的数量,例如"FancyClass1{T}.FancyMethod1{K}(T)"
    • 不确定你的意思。我从来不需要添加这些,它一直对我有用。你有一个不起作用的具体例子吗?如果是这样,请将其发布在某个地方(甚至自己提供答案。)
    • @Lasse,请参阅下面史蒂夫的回答和 cmets。您的答案未涵盖正确的 Intellisense 工具提示。
    【解决方案2】:

    TL;DR:

    “我如何引用FancyClass&lt;T&gt;?”

       /// <see cref="FancyClass{T}"/>
    

    FancyClass&lt;T&gt;.FancyMethod&lt;K&gt;(T value) 呢?”

       /// <see cref="FancyClass{T}.FancyMethod{K}(T)"/>
    

    “我如何引用FancyClass&lt;string&gt;?”

       /// <see cref="SomeType.SomeMethod(FancyClass{string})"/>
       /// <see cref="FancyClass{T}"/> whose generic type argument is <see cref="string"/>
    

    虽然您可以引用签名包含FancyClass&lt;string&gt;(例如作为参数类型)的方法,但您不能直接引用这种封闭的泛型类型。第二个示例解决了该限制。 (这可以在 MSDN refence page for the static System.String.Concat(IEnumerable&lt;string&gt;) method 上看到)。 :

    XML 文档注释cref 规则:

    • 用花括号 {} 将泛型类型参数列表括起来,而不是用 &lt;&gt; 尖括号括起来。这使您免于将后者转义为 &amp;lt;&amp;gt; — 请记住,文档 cmets 是 XML!

    • 如果包含前缀(例如 T: 用于类型,M: 用于方法,P: 用于属性,F: 用于字段),编译器将不会对引用执行任何验证,但只需将 cref 属性值直接复制到文档 XML 输出。因此,您必须使用适用于此类文件的特殊 "ID string" syntax:始终使用完全限定标识符,并使用反引号引用泛型类型参数(`n 用于类型,``n 用于方法)。

    • 如果省略前缀,则适用常规语言命名规则:您可以删除包含 using 语句的命名空间,并且可以使用语言的类型关键字,例如 @987654344 @ 而不是 System.Int32。此外,编译器将检查引用的正确性。

    XML 文档注释cref 备忘单:

    namespace X
    {
        using System;
    
        /// <see cref="I1"/>  (or <see cref="X.I1"/> from outside X)
        /// <see cref="T:X.I1"/>
        interface I1
        {
            /// <see cref="I1.M1(int)"/>  (or <see cref="M1(int)"/> from inside I1)
            /// <see cref="M:X.I1.M1(System.Int32)"/>
            void M1(int p);
    
            /// <see cref="I1.M2{U}(U)"/>
            /// <see cref="M:X.I1.M2``1(``0)"/>
            void M2<U>(U p);
    
            /// <see cref="I1.M3(Action{string})"/>
            /// <see cref="M:X.I1.M3(System.Action{System.String})"/>
            void M3(Action<string> p);
        }
    
        /// <see cref="I2{T}"/>
        /// <see cref="T:X.I2`1"/>
        interface I2<T>
        {
            /// <see cref="I2{T}.M1(int)"/>
            /// <see cref="M:X.I2`1.M1(System.Int32)"/>
            void M1(int p);
    
            /// <see cref="I2{T}.M2(T)"/>
            /// <see cref="M:X.I2`1.M2(`0)"/>
            void M2(T p);
    
            /// <see cref="I2{T}.M3{U}(U)"/>
            /// <see cref="M:X.I2`1.M3``1(``0)"/>
            void M3<U>(U p);
        }
    }
    

    【讨论】:

    • 如何仅引用T 部分?
    • 想通了:&lt;typeparamref name="T"/&gt;
    【解决方案3】:
    /// <summary>Uses a <see cref="FancyClass{T}" /> instance.</summary>
    

    顺便说一句,它出现在 .Net Framework 2.03.0 的 MSDN 文档中,但在 version 3.5 中消失了

    【讨论】:

    • T 的特定实例怎么样?像字符串?也许不可能?
    • 什么意思?你不能声明一个特定的版本,所以你也不能引用它。
    • 如果一个方法例如只返回 List。但不重要:)
    • 是的,我也想知道...... resharpers 在编写 FancyClass{string} 时会出现曲线,但在编写 FancyClass{String} 时不会......
    • “Think Before Coding”进行上述观察的原因是它不适用于 c# 别名。例如,您需要使用Int32 而不是intSingle 而不是float 等。(将此信息放在这里以防其他人偶然发现)
    【解决方案4】:

    到目前为止,没有一个答案完全适合我。除非完全解析,否则 ReSharper 不会将 see 标记转换为 Ctrl+可点击链接(例如 )。

    如果 OP 中的方法位于名为 Test 的命名空间中,则显示的方法的完全解析链接将是:

    &lt;see cref="M:Test.FancyClass`1.FancyMethod``1(`0)"/&gt;

    如你所见,在类类型参数的数量之前应该只有一个反引号,然后在方法类型参数的数量之前有两个反引号,然后参数是具有适当数量的零索引参数反引号。

    所以我们可以看到FancyClass有一个类类型参数,FancyMethod有一个类型参数,一个FancyClass参数类型的对象会被传递给方法。

    你可以在这个例子中更清楚地看到:

    namespace Test
    {
        public class FancyClass<A, B>
        {
            public void FancyMethod<C, D, E>(A a, B b, C c, D d, E e) { }
        }
    }
    

    链接变成:

    M:Test.FancyClass`2.FancyMethod``3(`0,`1,``0,``1,``2)

    或“具有两个类型参数的类,该类具有具有三个类型参数的方法,其中方法参数为ClassType1ClassType2MethodType1MethodType2MethodType3


    作为补充说明,我在任何地方都没有找到此文档,而且我不是天才,编译器告诉了我这一切。您所要做的就是创建一个测试项目enable XML documentation,然后插入您想要为其创建链接的代码,并在其上添加一个 XML 文档注释的开头 (///):

    namespace Test
    {
        public class FancyClass<T>
        {
            ///
            public string FancyMethod<K>(T value) { return "something fancy"; }
        }
    
        public class Test
        {
            public static void Main(string[] args) { }
        }
    }
    

    然后构建你的项目,输出的 XML 文档包含 doc->members->member 元素中 name 属性下的链接:

    <?xml version="1.0"?>
    <doc>
        <assembly>
            <name>Test</name>
        </assembly>
        <members>
            <member name="M:Test.FancyClass`1.FancyMethod``1(`0)">
    
            </member>
        </members>
    </doc>
    

    【讨论】:

    • 这应该会得到更多的支持,特别是因为找到正确符号的技巧,而不必经过反复试验。赞美我的男人
    【解决方案5】:

    进一步来自 Lasse 和 T.B.C 的回答:

    /// <see cref="T:FancyClass`1{T}"/> for more information.
    
    /// <see cref="M:FancyClass`1{T}.FancyMethod`1{K}(T)"/> for more information.
    

    还将正确提供工具提示,而他们的版本使用花括号来呈现它。

    【讨论】:

    • 使用 1 - 你愿意详细说明应该如何使用它吗?跨度>
    • 嗨,Jakub,这似乎确实不起作用。我也可以让工具提示正常工作的唯一方法是通过
    • 好的,我部分明白了。如果方法本身不是通用的(如在 List.Add() 中),则此方法有效: .
    • 似乎对我不起作用。我在我编写的通用扩展方法的注释标题中有 (将 ArrayList 转换为 List) 但 ReSharper 将其标记为语法错误,而 IntelliSense 只是逐字显示。 VS 2010/R# 6.1.37.86
    • 啊哈!我能够让 " 工作。因此,使用 T: 而不是花括号就可以了。它确实扩展了完整的命名空间,如果你不包含命名空间,这个技巧就不起作用,所以它并不完美,但它会做到。
    【解决方案6】:
    /// Here we discuss the use of <typeparamref name="TYourExcellentType"/>.
    /// <typeparam name="TYourExcellentType">Your exellent documentation</typeparam>
    

    【讨论】:

    • 请注意,其他答案涵盖了如何引用泛型类,这个答案向您展示了如何自己引用类型参数,这恰好是我想要做的。
    【解决方案7】:
    /// <see cref="FancyClass&lt;T>.FancyMethod&lt;K>(T)"/> for more information.
    

    【讨论】:

      【解决方案8】:

      这是我在其他地方给出的答案。它也适用于类和方法。

      我在堆栈溢出时尝试了所有方法,以获得适用于多种情况的结果。这是一个适合我的解决方案。 (这对其他人来说是主观的。)

      1. 产生可点击的链接。
      2. 将鼠标悬停在标识符上有效。
      3. 正确生成 .xml 文件。
      4. 在智能感知中不会产生错误。
      5. 适用于可为空的泛型类型参数。
      6. 在 Resharper 中工作,它是内置的 XML Doc 窗口(Resharper -> 编辑 -> 显示快速文档)
      7. 适用于 Atomineer Pro Documentaion Visual Studio Extension 的 XAM Doc Preview。
      8. 适用于泛型类型的泛型类型。

      示例 #1

        /// <summary>
        ///  This instance field holds a reference to the
        ///  <see cref="ConcurrentDictionary{Decimal, Boolean}"/> as
        ///  <see cref="T:ConcurrentDictionary&lt;decimal, bool?&gt;"/> that contains
        ///  the list of all PDF's that are currently opened and being displayed.
        /// </summary>
        private ConcurrentDictionary<decimal, bool?> openedPdfs = default!;
      
        Note: 
          The ConcurrentDictionary{Decimal, Boolean} will correctly produce a
          clickable link of ConcurrentDictionary{TKey, TValue} on hovering while
          T:ConcurrentDictionary&lt;decimal, bool?&gt; makes sure the reader gets
          information on what type TKey and TValue are.
      

      示例 #2(使用“T”)

        /// <summary>
        ///  This instance field holds a reference to the
        ///  <see cref="ConcurrentDictionary{TKey, TValue}"/> as
        ///  <see cref="T:ConcurrentDictionary&lt;decimal, bool?&gt;"/> that contains
        ///  the list of all PDF's that are currently opened and being displayed.
        /// </summary>
        private ConcurrentDictionary<decimal, bool?> openedPdfs = default!;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-11
        • 2021-04-08
        • 2020-12-20
        相关资源
        最近更新 更多