Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här självstudien tar du ett befintligt objektorienterat exempel (från föregående självstudie) och förbättrar det med xml-dokumentationskommentarer. Kommentarer till XML-dokumentationen ger användbara IntelliSense-knappbeskrivningar och kan delta i genererade API-referensdokument. Du får lära dig vilka element som förtjänar kommentarer, hur du använder kärntaggar som <summary>, <param>, <returns>, <value>, <remarks>, <example>, <seealso>, <exception>, och <inheritdoc> och hur konsekventa, målmedvetna kommentarer förbättrar underhållbarhet, upptäckbarhet och samarbete – utan att lägga till störningar. I slutet kommenterade du exemplets offentliga yta, skapade projektet för att generera XML-dokumentationsfilen och såg hur kommentarerna flödar direkt till utvecklarupplevelsen och nedströmsdokumentationsverktygen.
I den här handledningen kommer du att:
- Aktivera XML-dokumentationsutdata i ditt C#-projekt.
- Lägga till och strukturera XML-dokumentationskommentarer för typer och medlemmar.
- Skapa projektet och granska den genererade XML-dokumentationsfilen.
Förutsättningar
- .NET SDK
- Antingen Visual Studio eller Visual Studio Code med C# Dev Kit.
Aktivera XML-dokumentation
Ladda projektet du skapade i den föregående objektorienterade handledningen. Om du vill börja om på nytt klonar du exemplet från dotnet/docs lagringsplatsen under snippets/object-oriented-programming mappen .
Aktivera sedan XML-dokumentationsutdata så att kompilatorn genererar en .xml fil tillsammans med din sammansättning. Redigera projektfilen och lägg till (eller bekräfta) följande egenskap i ett <PropertyGroup> element:
<GenerateDocumentationFile>True</GenerateDocumentationFile>
Om du använder Visual Studio kan du aktivera detta med hjälp av egenskapssidan "build".
Skapa projektet. Kompilatorn skapar en XML-fil som aggregerar alla /// kommentarer från offentligt synliga typer och medlemmar. Filen matar IntelliSense-verktygstips, statiska analysverktyg och dokumentationsgenereringssystem.
Skapa projektet nu. Du ser varningar för alla offentliga medlemmar som saknar <summary> kommentarer. Behandla varningarna som en to-do lista som hjälper dig att tillhandahålla fullständig, avsiktlig dokumentation. Öppna den genererade XML-filen (den finns bredvid byggutdata) och granska den ursprungliga strukturen. Först är avsnittet <members> tomt eftersom du inte har lagt till kommentarer ännu:
<?xml version="1.0"?>
<doc>
<assembly>
<name>oo-programming</name>
</assembly>
<members>
</members>
</doc>
När filen är på plats börjar du lägga till riktade XML-kommentarer och kontrollerar omedelbart hur var och en visas i de genererade utdata. Börja med Transaction registertypen:
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);
Lägga till dokumentationskommentar
Nu går du igenom byggvarningarna för att lägga till kortfattad, användbar dokumentation till BankAccount typen. Varje varning pekar ut en offentlig medlem som saknar ett <summary> (eller annat obligatoriskt) element. Behandla varningslistan som en checklista. Undvik att lägga till brus: fokusera på att beskriva avsikter, invarianter och viktiga användningsbegränsningar – hoppa över att upprepa uppenbara typnamn eller parametertyper.
- Skapa projektet igen. I Visual Studio eller Visual Studio Code öppnar du panelen Fellista/Problem och filtrerar efter dokumentationsvarningar (CS1591). På kommandoraden kör du en byggprocess och granskar varningarna som visas på konsolen.
- Gå till den första varningen (
BankAccountklassen). På raden ovanför deklarationen skriver du///. Redigeraren strukturerar ett<summary>-element. Ersätt platshållaren med en enda, åtgärdsfokuserad mening. Meningen förklarar rollen för kontot i domänen. Den spårar till exempel transaktioner och framtvingar ett minsta saldo. - Lägg bara till
<remarks>om du behöver förklara beteendet. Exempel är hur minsta saldoframtvingande fungerar eller hur kontonummer genereras. Håll kommentarerna korta. - För varje egenskap (
Number,Owner,Balance), ange///och skriv en<summary>som anger vad värdet representerar – inte hur en trivial getter returnerar det. Om en egenskap beräknar ett värde (till exempelBalance) lägger du till ett<value>element som förtydligar beräkningen. - För varje konstruktor, lägg till
<summary>plus<param>-element som beskriver innebörden av varje argument, inte bara återge parameternamnet. Om en överlagring delegeras till en annan ska du lägga till ett koncist<remarks>-element. - För metoder som kan kasta, lägg till
<exception>taggar för varje avsiktliga undantagstyper. Beskriv villkoret som utlöser det. Dokumentera inte undantag som genereras av argumentverifieringshjälpare om de inte ingår i det offentliga kontraktet. - För metoder som returnerar ett värde lägger du till
<returns>med en kort beskrivning av vad anropare får. Undvik att upprepa metodnamnet eller den hanterade typen. - Arbeta med basklassen
BankAccountförst.
Din version bör se ut ungefär så här:
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() { }
}
När du är klar öppnar du den återskapade XML-filen och bekräftar att varje medlem visas med dina nya element. En trimmad del kan se ut så här:
<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>
Tips/Råd
Behåll sammanfattningar till en enda mening. Om du behöver mer än en flyttar du den sekundära kontexten till <remarks>.
Använda <inheritdoc/> i härledda klasser
Om du härleder från BankAccount (som till exempel en SavingsAccount som tillämpar ränta) kan du ärva basdokumentationen istället för att kopiera den. Lägg till ett självslutande <inheritdoc/> element i dokumentationsblocket för den härledda medlemmen. Du kan fortfarande lägga till fler element (till exempel extra <remarks> information) efter <inheritdoc/> för att dokumentera det specialiserade beteendet:
/// <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
Anmärkning
<inheritdoc/> minskar dupliceringen och hjälper till att upprätthålla konsekvens när du uppdaterar bastypsdokumentationen senare.
När du har dokumenterat den offentliga ytan skapar du en sista gång för att bekräfta att det inte finns några återstående CS1591-varningar. Projektet skapar nu användbara IntelliSense och en strukturerad XML-fil som är redo för publicering av arbetsflöden.
Du kan se det fullständiga kommenterade exemplet i källmappen för dotnet/docs-lagringsplatsen på GitHub.
Skapa utdata från kommentarer
Du kan utforska mer genom att prova något av dessa verktyg för att skapa utdata från XML-kommentarer:
- DocFX: DocFX är en API-dokumentationsgenerator för .NET, som för närvarande stöder C#, Visual Basic och F#. Du kan också anpassa den genererade referensdokumentationen. DocFX skapar en statisk HTML-webbplats från källkoden och Markdown-filerna. DocFX ger dig också flexibiliteten att anpassa webbplatsens layout och stil via mallar. Du kan också skapa anpassade mallar.
- Sandcastle: Sandcastle-verktygen skapar hjälpfiler för hanterade klassbibliotek som innehåller både konceptuella och API-referenssidor. Sandcastle-verktygen är kommandoradsbaserade och har inga GUI-klientdelar, projekthanteringsfunktioner eller automatiserad byggprocess. Sandcastle Help File Builder tillhandahåller fristående GUI och kommandoradsbaserade verktyg för att skapa en hjälpfil på ett automatiserat sätt. Ett Visual Studio-integreringspaket är också tillgängligt för det så att hjälpprojekt kan skapas och hanteras helt inifrån Visual Studio.
- Doxygen: Doxygen genererar en webbläsare för onlinedokumentation (i HTML) eller en offlinereferenshandbok (i LaTeX) från en uppsättning dokumenterade källfiler. Det finns också stöd för att generera utdata i RTF (MS Word), PostScript, hyperlänkad PDF, komprimerad HTML, DocBook och Unix manuella sidor. Du kan konfigurera Doxygen för att extrahera kodstrukturen från odokumenterade källfiler.