依赖属性的XML文档说明

8

如何最好地记录依赖属性?

我应该在字段上放置xml文档注释吗:

/// <summary>Documentation goes here</summary>
public static readonly DependencyProperty NameProperty = 
        DependencyProperty.Register(...)

或者在属性上:
/// <summary>and/or here?</summary>
public string Name{ get{...} set{...} }

还是我真的需要记录(并维护)这两者吗?


感谢修正拼写错误,Jeff :-) - Stefan
2个回答

2

好的,这是我想到的解决方案。

我在依赖属性中使用了一个特殊的XML标签,它将被XSL转换替换。虽然没有使用该标签也是可以实现的,但是Visual Studio会发出警告,因为该字段未经记录。

/// <dpdoc />
public static readonly DependencyProperty PositionProperty = 
    DependencyProperty.Register(...)

C# 属性的文档与平常一样,只需确保不要忘记值的描述。
/// <summary>Gets or sets the position of this element</summary>
/// <value>Position (in pixel) relative to the parent's upper left corner.</value>
/// <remarks><para>
/// If either the <c>x</c> or <c>y</c> component is <c>+inf</c> this indicates...
/// </para></remarks>
public Point Position{ get{...} set{...} }

在构建过程中,Visual Studio 会从这些注释中创建一个 XML 文件。通过一些 xsl 转换,dpdoc 节点会被属性文档的修改版本所替换。生成的 XML 文件与我们精心记录属性标识符的文件相同。它甚至包括一个简短的注释,说明还有另一种访问变量的方式:

/// <summary>Position (in pixel) relative to the parent's upper left corner.</summary>
/// <remarks><para>
/// If either the <c>x</c> or <c>y</c> component is <c>+inf</c> this indicates...
/// <para>
/// This dependency property can be accessed via the <see cref="Position"/> property.
/// </para>
/// </para></remarks>
public static readonly DependencyProperty PositionProperty = 
    DependencyProperty.Register(...)

那样的话,两个API都有适当的文档,我们不需要在代码中重复文档。可以在构建后事件中完成xsl转换或集成到文档生成过程中。
以下是xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="//dpdoc">
        <xsl:variable name="propertyName" select="concat('P:', substring(../@name,3,string-length(../@name)-10))" />
        <summary>
            <xsl:apply-templates select="//member[@name=$propertyName]/value/node()"/>
        </summary>
        <xsl:apply-templates select="//member[@name=$propertyName]/*[not(self::remarks)][not(self::summary)][not(self::value)]"/>
        <remarks>
            <xsl:apply-templates select="//member[@name=$propertyName]/remarks/node()"/>
            <para>
                This dependency property can be accessed via the
                <see>
                    <xsl:attribute name="cref"><xsl:value-of select="$propertyName"/></xsl:attribute>
                </see>
                property.
            </para>
        </remarks>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

为什么我希望这样做:

  • 属性标识符(DependencyProperty实例)和属性本身都是公共的,因此可以合法地用于访问该属性。因此,我们有两个 API 可以访问同一个逻辑变量。
  • 代码文档应该描述看不到的内容。在这种情况下,它应该描述属性的含义、值以及如何正确使用它。由于属性标识符和 C# 属性引用了相同的逻辑变量,它们具有相同的含义。
  • 用户可以自由选择两种访问逻辑变量的方式,并且不必意识到另一种方式。因此,两者都必须得到适当的文档支持。
  • 复制粘贴代码注释和复制粘贴代码一样糟糕。

1

你应该记录和维护两者。一个是依赖属性,另一个是常规属性,只是作为访问该依赖属性实现的。它们不是同一件事,需要单独的文档。


1
嗯,当然有技术上的区别。但我不认为文档会有太大差异。基本上两者都需要描述值的含义。除此之外,只是API的差异而已。 - Stefan
这并不是真的。实例属性的实现有些无关紧要。调用者永远不应该依赖于实现。你应该向微软学习,他们非常清楚地认为记录这两个项目是必要的。毕竟,一个用户不应该需要知道他们必须查看另一个项目以获取信息。假设这两个项目是相关的,很容易导致错误的假设。 - Jeff Yates
1
微软的属性字段文档真的很差。它只是简单地写着“标识[属性名称]依赖属性”。这是每个人从声明中一眼就能看到的,完全没有用处(可能甚至是自动生成的)。它应该记录属性的含义。另外一个问题是:属性的实现也很重要!首先,WPF假定属性直接由dp支持,因为它绕过属性并直接访问dp。 - Stefan
毕竟,一个用户不应该需要知道他们必须查看另一个信息。假设这两个是相关的会导致错误的假设。我完全同意你的观点。现在看看微软如何记录DPs!为了找出那个东西的用途,你必须找到相应的C#属性并阅读文档。 - Stefan
1
抱歉,我并不是在评论微软文档的质量 - 我只是指出提供文档非常重要。微软提供的文档比让开发人员猜测要好得多。至少从微软的文档中,你知道该去哪里查找,而不是被猜测所困扰。 - Jeff Yates

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接