Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este tutorial, tomará un ejemplo orientado a objetos existente (del tutorial anterior) y lo mejorará con comentarios de documentación XML. Los comentarios de documentación XML proporcionan información sobre herramientas útiles de IntelliSense y pueden participar en documentos de referencia de API generados. Aprenderá qué elementos merecen comentarios, cómo usar etiquetas principales como <summary>, <param><returns><value><remarks><example><seealso><exception>, y cómo los comentarios coherentes y <inheritdoc>propósitos mejoran la capacidad de mantenimiento, la detectabilidad y la colaboración, sin agregar ruido. Al final, ha anotado la superficie pública del ejemplo, ha creado el proyecto para emitir el archivo de documentación XML y ha visto cómo esos comentarios fluyen directamente a la experiencia del desarrollador y a las herramientas de documentación de nivel inferior.
En este tutorial, usted hará lo siguiente:
- Habilite la salida de documentación XML en el proyecto de C#.
- Agregar y estructurar comentarios de documentación XML a tipos y miembros.
- Compile el proyecto e inspeccione el archivo de documentación XML generado.
Prerrequisitos
Habilitación de la documentación XML
Cargue el proyecto que ha creado en el tutorial orientado a objetos anterior. Si prefiere empezar de nuevo, clone el ejemplo del dotnet/docs repositorio en la snippets/object-oriented-programming carpeta .
A continuación, habilite la salida de la documentación XML para que el compilador emita un .xml archivo junto con el ensamblado. Edite el archivo del proyecto y agregue (o confirme) la siguiente propiedad dentro de un <PropertyGroup> elemento:
<GenerateDocumentationFile>True</GenerateDocumentationFile>
Si usa Visual Studio, puede habilitarlo mediante la página de propiedades "build".
Compile el proyecto. El compilador genera un archivo XML que agrega todos los /// comentarios de los tipos y miembros visibles públicamente. Ese archivo alimenta los tooltips de IntelliSense, las herramientas de análisis estáticos y los sistemas de generación de documentación posteriores.
Compile el proyecto ahora. Verá advertencias sobre los miembros públicos que carecen de comentarios <summary>. Trate esas advertencias como una lista de tareas que le ayuda a proporcionar documentación completa e intencional. Abra el archivo XML generado (junto a la salida de la compilación) e inspeccione la estructura inicial. Al principio, la <members> sección está vacía porque aún no ha agregado comentarios:
<?xml version="1.0"?>
<doc>
<assembly>
<name>oo-programming</name>
</assembly>
<members>
</members>
</doc>
Con el archivo en contexto, empiece a agregar comentarios XML de destino e compruebe inmediatamente cómo aparece cada uno en la salida generada. Comience con el Transaction tipo de registro:
namespace OOProgramming;
/// <summary>
/// Represents an immutable financial transaction with an amount, date, and descriptive notes.
/// </summary>
/// <param name="Amount">The transaction amount. Positive values represent credits/deposits, negative values represent debits/withdrawals.</param>
/// <param name="Date">The date and time when the transaction occurred.</param>
/// <param name="Notes">Descriptive notes or memo text associated with the transaction.</param>
public record Transaction(decimal Amount, DateTime Date, string Notes);
Adición de comentarios de documentación
Ahora navega por las advertencias de compilación para agregar documentación útil y concisa al tipo BankAccount. Cada advertencia identifica un miembro público que carece de un <summary> elemento (u otro requerido). Trate la lista de advertencias como una lista de comprobación. Evite agregar ruido: céntrese en describir las restricciones de uso importantes, las invariantes y la intención: omita la indicación de tipos obvios o tipos de parámetros.
- Vuelva a compilar el proyecto. En Visual Studio o Visual Studio Code, abra el panel Lista de errores o problemas y filtre por advertencias de documentación (CS1591). En la línea de comandos, ejecute una compilación y revise las advertencias emitidas en la consola.
- Vaya a la primera advertencia (clase
BankAccount). En la línea situada encima de la declaración, escriba///. El editor estructura un elemento<summary>. Reemplace el marcador de posición por una sola oración centrada en la acción. En la frase se explica el rol de la cuenta en el dominio. Por ejemplo, realiza un seguimiento de las transacciones y aplica un saldo mínimo. - Agregue
<remarks>solo si necesita explicar el comportamiento. Algunos ejemplos incluyen cómo funciona el cumplimiento mínimo del equilibrio o cómo se generan los números de cuenta. Mantenga los comentarios cortos. - Para cada propiedad (
Number,Owner,Balance), escriba///y escriba un<summary>que indique lo que representa el valor, no cómo lo devuelve un captador trivial. Si una propiedad calcula un valor (comoBalance), agregue un<value>elemento que aclara el cálculo. - Para cada constructor, agregue elementos
<summary>y<param>que describen el significado de cada argumento, no solo indicando el nombre del parámetro. Si una sobrecarga delega a otra, agregue un elemento conciso<remarks>. - Para los métodos que pueden lanzar excepciones, agregue la etiqueta
<exception>para cada tipo de excepción intencionada. Describir la condición que la desencadena. No documente excepciones producidas por asistentes de validación de argumentos a menos que formen parte del contrato público. - Para los métodos que devuelven un valor, agregue
<returns>con una breve descripción de lo que reciben los llamadores. Evite repetir el nombre del método o el tipo administrado. - Trabaje primero con la
BankAccountclase base.
La versión debe tener un aspecto similar al código siguiente:
namespace OOProgramming;
/// <summary>
/// Represents a bank account with basic banking operations including deposits, withdrawals, and transaction history.
/// Supports minimum balance constraints and provides extensible month-end processing capabilities.
/// </summary>
public class BankAccount
{
/// <summary>
/// Gets the unique account number for this bank account.
/// </summary>
/// <value>A string representation of the account number, generated sequentially.</value>
public string Number { get; }
/// <summary>
/// Gets or sets the name of the account owner.
/// </summary>
/// <value>The full name of the person who owns this account.</value>
public string Owner { get; set; }
/// <summary>
/// Gets the current balance of the account by calculating the sum of all transactions.
/// </summary>
/// <value>The current account balance as a decimal value.</value>
public decimal Balance => _allTransactions.Sum(i => i.Amount);
private static int s_accountNumberSeed = 1234567890;
private readonly decimal _minimumBalance;
/// <summary>
/// Initializes a new instance of the BankAccount class with the specified owner name and initial balance.
/// Uses a default minimum balance of 0.
/// </summary>
/// <param name="name">The name of the account owner.</param>
/// <param name="initialBalance">The initial deposit amount for the account.</param>
/// <remarks>
/// This constructor is a convenience overload that calls the main constructor with a minimum balance of 0.
/// If the initial balance is greater than 0, it will be recorded as the first transaction with the note "Initial balance".
/// The account number is automatically generated using a static seed value that increments for each new account.
/// </remarks>
public BankAccount(string name, decimal initialBalance) : this(name, initialBalance, 0) { }
/// <summary>
/// Initializes a new instance of the BankAccount class with the specified owner name, initial balance, and minimum balance constraint.
/// </summary>
/// <param name="name">The name of the account owner.</param>
/// <param name="initialBalance">The initial deposit amount for the account.</param>
/// <param name="minimumBalance">The minimum balance that must be maintained in the account.</param>
/// <remarks>
/// This is the primary constructor that sets up all account properties. The account number is generated automatically
/// using a static seed value. If an initial balance is provided and is greater than 0, it will be added as the first
/// transaction. The minimum balance constraint will be enforced on all future withdrawal operations through the
/// <see cref="CheckWithdrawalLimit"/> method.
/// </remarks>
public BankAccount(string name, decimal initialBalance, decimal minimumBalance)
{
Number = s_accountNumberSeed.ToString();
s_accountNumberSeed++;
Owner = name;
_minimumBalance = minimumBalance;
if (initialBalance > 0)
MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}
private readonly List<Transaction> _allTransactions = [];
/// <summary>
/// Makes a deposit to the account by adding a positive transaction.
/// </summary>
/// <param name="amount">The amount to deposit. Must be positive.</param>
/// <param name="date">The date when the deposit is made.</param>
/// <param name="note">A descriptive note about the deposit transaction.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the deposit amount is zero or negative.</exception>
/// <remarks>
/// This method creates a new <see cref="Transaction"/> object with the specified amount, date, and note,
/// then adds it to the internal transaction list. The transaction amount must be positive - negative amounts
/// are not allowed for deposits. The account balance is automatically updated through the Balance property
/// which calculates the sum of all transactions. There are no limits or restrictions on deposit amounts.
/// </remarks>
public void MakeDeposit(decimal amount, DateTime date, string note)
{
if (amount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
}
var deposit = new Transaction(amount, date, note);
_allTransactions.Add(deposit);
}
/// <summary>
/// Makes a withdrawal from the account by adding a negative transaction.
/// Checks withdrawal limits and minimum balance constraints before processing.
/// </summary>
/// <param name="amount">The amount to withdraw. Must be positive.</param>
/// <param name="date">The date when the withdrawal is made.</param>
/// <param name="note">A descriptive note about the withdrawal transaction.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when the withdrawal amount is zero or negative.</exception>
/// <exception cref="InvalidOperationException">Thrown when the withdrawal would cause the balance to fall below the minimum balance.</exception>
/// <remarks>
/// This method first validates that the withdrawal amount is positive, then checks if the withdrawal would
/// violate the minimum balance constraint by calling <see cref="CheckWithdrawalLimit"/>. The withdrawal is
/// recorded as a negative transaction amount. If the withdrawal limit check returns an overdraft transaction
/// (such as a fee), that transaction is also added to the account. The method enforces business rules through
/// the virtual CheckWithdrawalLimit method, allowing derived classes to implement different withdrawal policies.
/// </remarks>
public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
if (amount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
}
Transaction? overdraftTransaction = CheckWithdrawalLimit(Balance - amount < _minimumBalance);
Transaction? withdrawal = new(-amount, date, note);
_allTransactions.Add(withdrawal);
if (overdraftTransaction != null)
_allTransactions.Add(overdraftTransaction);
}
/// <summary>
/// Checks whether a withdrawal would violate the account's minimum balance constraint.
/// This method can be overridden in derived classes to implement different withdrawal limit policies.
/// </summary>
/// <param name="isOverdrawn">True if the withdrawal would cause the balance to fall below the minimum balance.</param>
/// <returns>A Transaction object representing any overdraft fees or penalties, or null if no additional charges apply.</returns>
/// <exception cref="InvalidOperationException">Thrown when the withdrawal would cause an overdraft and the account type doesn't allow it.</exception>
protected virtual Transaction? CheckWithdrawalLimit(bool isOverdrawn)
{
if (isOverdrawn)
{
throw new InvalidOperationException("Not sufficient funds for this withdrawal");
}
else
{
return default;
}
}
/// <summary>
/// Generates a detailed account history report showing all transactions with running balance calculations.
/// </summary>
/// <returns>A formatted string containing the complete transaction history with dates, amounts, running balances, and notes.</returns>
/// <remarks>
/// This method creates a formatted report that includes a header row followed by all transactions in chronological order.
/// Each row shows the transaction date (in short date format), the transaction amount, the running balance after that
/// transaction, and any notes associated with the transaction. The running balance is calculated by iterating through
/// all transactions and maintaining a cumulative total. The report uses tab characters for column separation and
/// is suitable for display in console applications or simple text outputs.
/// </remarks>
public string GetAccountHistory()
{
var report = new System.Text.StringBuilder();
decimal balance = 0;
report.AppendLine("Date\t\tAmount\tBalance\tNote");
foreach (var item in _allTransactions)
{
balance += item.Amount;
report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
}
return report.ToString();
}
/// <summary>
/// Performs month-end processing for the account. This virtual method can be overridden in derived classes
/// to implement specific month-end behaviors such as interest calculations, fee assessments, or statement generation.
/// </summary>
/// <remarks>
/// The base implementation of this method does nothing, providing a safe default for basic bank accounts.
/// Derived classes such as savings accounts or checking accounts can override this method to implement
/// account-specific month-end processing. Examples include calculating and applying interest payments,
/// assessing monthly maintenance fees, generating account statements, or performing regulatory compliance checks.
/// This method is typically called by banking systems at the end of each month as part of batch processing operations.
/// </remarks>
public virtual void PerformMonthEndTransactions() { }
}
Cuando haya terminado, abra el archivo XML regenerado y confirme que cada miembro aparece con los nuevos elementos. Una parte recortada podría tener este aspecto:
<member name="T:OOProgramming.BankAccount">
<summary>Represents a bank account that records transactions and enforces an optional minimum balance.</summary>
<remarks>Account numbers are generated sequentially when each instance is constructed.</remarks>
</member>
<member name="P:OOProgramming.BankAccount.Balance">
<summary>Gets the current balance based on all recorded transactions.</summary>
<value>The net sum of deposits and withdrawals.</value>
</member>
Sugerencia
Mantenga resúmenes en una sola oración. Si necesita más de una, mueva el contexto secundario a <remarks>.
Uso <inheritdoc/> en clases derivadas
Si deriva de BankAccount (por ejemplo, un SavingsAccount que aplica interés), puede heredar la documentación base en lugar de copiarla. Agregue un elemento de autocierre <inheritdoc/> dentro del bloque de documentación del miembro derivado. Todavía puede anexar más elementos (como detalles adicionales <remarks>) después de <inheritdoc/> para documentar el comportamiento especializado:
/// <inheritdoc/>
/// <remarks>
/// An interest-earning account is a specialized savings account that rewards customers for maintaining higher balances.
/// Interest is only earned when the account balance exceeds $500, encouraging customers to maintain substantial deposits.
/// The annual interest rate of 2% is applied monthly to qualifying balances, providing a simple savings incentive.
/// This account type uses the standard minimum balance of $0 from the base <see cref="BankAccount"/> class.
/// </remarks>
public class InterestEarningAccount : BankAccount
Nota:
<inheritdoc/> reduce la duplicación y ayuda a mantener la coherencia al actualizar la documentación de tipos base más adelante.
Después de terminar de documentar la superficie pública, genere una última vez para confirmar que no hay advertencias del tipo CS1591 restantes. El proyecto ahora genera IntelliSense útil y un archivo XML estructurado listo para publicar flujos de trabajo.
Puede ver el ejemplo anotado completo en la carpeta de origen del repositorio dotnet/docs en GitHub.
Generar producción a partir de los comentarios
Para explorar más, pruebe cualquiera de estas herramientas para crear resultados a partir de comentarios XML:
- DocFX: DocFX es un generador de documentación de API para .NET, que actualmente admite C#, Visual Basic y F#. También permite personalizar la documentación de referencia generada. DocFX compila un sitio web HTML estático a partir del código fuente y los archivos Markdown. Además, DocFX le proporciona la flexibilidad para personalizar el diseño y el estilo de su sitio web a través de plantillas. También puede crear plantillas personalizadas.
- Sandcastle: las herramientas de Sandcastle crean archivos de ayuda para bibliotecas de clases administradas que contienen páginas de referencia conceptuales y api. Las herramientas de Sandcastle se basan en la línea de comandos y no tienen características de front-end de GUI, de administración de proyectos ni de proceso de compilación automatizado. El Generador de archivos de ayuda de Sandcastle proporciona gui independiente y herramientas basadas en línea de comandos para crear un archivo de ayuda de forma automatizada. También hay disponible un paquete de integración de Visual Studio para que los proyectos de ayuda se puedan crear y administrar completamente desde Visual Studio.
- Doxygen: Doxygen genera un explorador de documentación en línea (en HTML) o un manual de referencia sin conexión (en LaTeX) a partir de un conjunto de archivos de origen documentados. También se admite la generación de resultados en RTF (MS Word), PostScript, PDF con hipervínculos, HTML comprimido, DocBook y páginas manuales de Unix. Puede configurar Doxygen para extraer la estructura de código de los archivos de origen no documentados.