Ok, esto es lo que se me ocurrió.
Uso una etiqueta xml especial en las propiedades de dependencia que se reemplazarán por una transformación xsl. Sería posible hacerlo sin él, pero entonces Visual Studio emite una advertencia porque el campo aparece sin documentar.
/// <dpdoc />
public static readonly DependencyProperty PositionProperty =
DependencyProperty.Register(...)
La propiedad de C# está documentada como siempre, solo asegúrese de no olvidar la descripción del valor.
/// <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 crea un archivo xml a partir de esos comentarios durante la construcción. Con una pequeña transformación xsl, el nodo dpdoc
se reemplaza por una versión modificada de la documentación de la propiedad. El archivo xml resultante es el mismo que si bien documentamos el identificador de propiedad. Incluso incluye una breve nota que hay una forma alternativa de acceder a la variable:
/// <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(...)
De esta manera, ambos de la API tienen la documentación adecuada y que no es necesario duplicar la documentación en el código. La transformación xsl se puede realizar en los eventos posteriores a la construcción o integrarse en el proceso de generación de documentación.
Aquí está el 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>
Por qué quiero tener de esa manera:
- Tanto el identificador de propiedad (el
DependencyProperty
ejemplo) y la propiedad, son públicos y por lo tanto puede legalmente ser utilizado para acceder a la propiedad. Tenemos dos API para la misma variable lógica.
- La documentación del código debe describir lo que aún no está allí para ver. En este contexto, debe describir el significado de la propiedad y su valor y cómo usarlo correctamente. Dado que tanto el identificador de propiedad como la propiedad C# hacen referencia a la misma variable lógica, tienen el mismo significado.
- El usuario puede elegir libremente una de las dos formas de acceder a la variable lógica y no tener en cuenta la otra. Los dos deben documentarse adecuadamente.
- Copiar y pegar los comentarios del código es tan malo como copiar y pegar el código.
gracias por arreglar el typo jeff :-) – Stefan