Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V tomto kurzu získáte existující objektově orientované ukázky (z předchozího kurzu) a vylepšíte ji pomocí komentářů dokumentace XML. Komentáře dokumentace XML poskytují užitečné IntelliSense tooltipy a mohou být součástí generovaných referenčních dokumentů API. Dozvíte se, které prvky si zaslouží komentáře, jak používat základní značky, jako <summary>, <param>, <returns>, <value>, <remarks>, <example>, <seealso>, <exception> a <inheritdoc> a jak konzistentní, účelné komentování zlepšuje udržovatelnost, dohledatelnost a spolupráci – bez přidání zbytečného šumu. Nakonec jste anotovali veřejnou plochu ukázky, vytvořili projekt pro generování souboru dokumentace XML a viděli jste, jak tyto komentáře proudí přímo do vývojářského prostředí a nástrojů pro podřízenou dokumentaci.
V tomto kurzu se naučíte:
- Povolte výstup dokumentace XML v projektu jazyka C#.
- Přidávání a strukturování komentářů dokumentace XML k typům a členům
- Sestavte projekt a zkontrolujte vygenerovaný soubor dokumentace XML.
Požadavky
- Sada .NET SDK
- Visual Studio nebo Visual Studio Code s C# Dev Kit
Povolení dokumentace XML
Načtěte projekt, který jste vytvořili v předchozím objektově orientovaném kurzu. Pokud chcete začít znovu, naklonujte ukázku dotnet/docs z úložiště pod složkou snippets/object-oriented-programming .
Dále povolte výstup dokumentace XML, aby kompilátor spolu se sestavením vygeneroval soubor s dokumentací XML. Upravte soubor projektu a do elementu <PropertyGroup> přidejte (nebo potvrďte) následující vlastnost:
<GenerateDocumentationFile>True</GenerateDocumentationFile>
Pokud používáte Visual Studio, můžete to povolit na stránce vlastností "sestavení".
Zkompilujte projekt. Kompilátor vytvoří soubor XML, který agreguje všechny /// komentáře z veřejně viditelných typů a členů. Tento soubor podává nápovědy IntelliSense, nástroje statické analýzy a následné systémy generování dokumentace.
Sestavte projekt nyní. Zobrazí se upozornění u všech veřejných členů, u nichž chybí komentáře <summary>. Upozornění můžete považovat za úkolníček, který vám pomůže poskytnout úplnou a záměrnou dokumentaci. Otevřete vygenerovaný soubor XML (je vedle výstupu sestavení) a zkontrolujte počáteční strukturu. Zpočátku je <members> oddíl prázdný, protože jste nepřidali zatím komentáře:
<?xml version="1.0"?>
<doc>
<assembly>
<name>oo-programming</name>
</assembly>
<members>
</members>
</doc>
Se souborem začněte přidávat cílové komentáře XML a okamžitě ověřte, jak se jednotlivé komentáře zobrazují ve vygenerovaném výstupu. Začněte typem záznamu Transaction :
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);
Přidání komentářů k dokumentaci
Teď cyklicky procházíte upozorněními sestavení a přidáte stručnou a užitečnou dokumentaci k BankAccount typu. Každé upozornění označuje veřejného člena, kterému chybí prvek <summary> nebo jiný povinný prvek. Seznam upozornění považujete za kontrolní seznam. Vyhněte se přidávání šumu: zaměřte se na popis záměru, invariantů a důležitých omezení použití – přeskočte přecházení jasných názvů typů nebo typů parametrů.
- Znovu sestavte projekt. V nástroji Visual Studio nebo Visual Studio Code otevřete panel Seznam chyb / Problémy a vyfiltrujte upozornění dokumentace (CS1591). Na příkazovém řádku spusťte sestavení a zkontrolujte upozornění vygenerované do konzoly.
- Přejděte na první upozornění (
BankAccounttřída). Na řádku nad deklarací zadejte///. Editor vygeneruje<summary>prvek. Zástupný symbol nahraďte jednou větou zaměřenou na akci. Věta vysvětluje roli účtu v doméně. Sleduje například transakce a vynucuje minimální zůstatek. - Přidejte
<remarks>pouze v případě, že potřebujete vysvětlit chování. Příklady zahrnují, jak funguje vynucení minimálního zůstatku nebo jak se generují čísla účtů. Mějte krátké poznámky. - Pro každou vlastnost (
Number,Owner,Balance) zadejte///a napište<summary>, který uvádí, co hodnota představuje – ne způsob, jakým ji vrací triviální getter. Pokud vlastnost vypočítá hodnotu (napříkladBalance), přidejte<value>prvek, který objasňuje výpočet. - Pro každý konstruktor přidejte
<summary>plus<param>elementy, které popisují význam každého argumentu, a nejen přejímají název parametru. Pokud jedno přetížení deleguje na jiné, přidejte stručnou strukturu<remarks>. - Pro metody, které mohou vyvolat výjimky, přidejte
<exception>značky pro každou úmyslnou výjimku. Popište podmínku, která ji aktivuje. Nezdokumentujte výjimky vyvolané pomocnými rutinami pro ověřování argumentů, pokud nejsou součástí veřejného kontraktu. - Pro metody, které vracejí hodnotu, přidejte
<returns>krátký popis toho, co volající obdrží. Vyhněte se opakování názvu metody nebo spravovaného typu. - Pracujte nejprve se základní třídou
BankAccount.
Vaše verze by měla vypadat přibližně takto:
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() { }
}
Až budete hotovi, otevřete znovu vygenerovaný soubor XML a potvrďte, že se každý člen zobrazí s vašimi novými prvky. Oříznutá část může vypadat takto:
<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>
Návod
Uchovávejte souhrny na jednu větu. Pokud potřebujete více než jeden, přesuňte sekundární kontext do <remarks>.
Použijte <inheritdoc/> v odvozených třídách
Pokud pocházíte z BankAccount, můžete, například z SavingsAccount, který aplikuje úroky, místo kopírování zdědit výchozí dokumentaci. Do bloku dokumentace odvozeného člena přidejte samozavírací element <inheritdoc/>. Další prvky, jako jsou podrobnosti navíc <remarks>, můžete přidat za <inheritdoc/> pro dokumentaci specializovaného chování:
/// <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
Poznámka:
<inheritdoc/> snižuje duplicitu a pomáhá udržovat konzistenci při pozdější aktualizaci dokumentace základního typu.
Po dokončení dokumentování veřejného povrchu vytvořte jeden konečný čas, abyste potvrdili, že neexistují žádná další upozornění CS1591. Váš projekt teď vytváří užitečnou technologii IntelliSense a strukturovaný soubor XML připravený pro publikování pracovních postupů.
Úplnou ukázku s poznámkami si můžete prohlédnout ve zdrojové složce úložiště dotnet/docs na GitHubu.
Vytvoření výstupu z komentářů
Další informace můžete prozkoumat pomocí některého z těchto nástrojů k vytvoření výstupu z komentářů XML:
- DocFX: DocFX je generátor dokumentace rozhraní API pro .NET, který aktuálně podporuje C#, Visual Basic a F#. Umožňuje také přizpůsobit vygenerovanou referenční dokumentaci. DocFX vytvoří statický web HTML ze zdrojového kódu a souborů Markdownu. DocFX vám také poskytuje flexibilitu při přizpůsobení rozložení a stylu webu prostřednictvím šablon. Můžete také vytvořit vlastní šablony.
- Sandcastle: Nástroje Sandcastle vytvářejí soubory nápovědy pro knihovny spravovaných tříd obsahující koncepční i referenční stránky rozhraní API. Nástroje Sandcastle jsou založené na příkazovém řádku a nemají žádné front-endové grafické uživatelské rozhraní, funkce řízení projektů ani automatizovaný proces sestavení. Tvůrce souborů nápovědy Sandcastle poskytuje samostatné grafické uživatelské rozhraní a nástroje založené na příkazovém řádku pro automatické sestavení souboru nápovědy. K dispozici je také integrační balíček sady Visual Studio, aby bylo možné vytvářet a spravovat projekty nápovědy zcela ze sady Visual Studio.
- Doxygen: Doxygen generuje online prohlížeč dokumentace (v HTML) nebo offline referenční příručku (v LaTeX) ze sady dokumentovaných zdrojových souborů. K dispozici je také podpora generování výstupu ve formátech RTF (MS Word), PostScript, hypertextového formátu PDF, komprimovaného HTML, DocBook a Unixových manuálových stránek. Doxygen můžete nakonfigurovat tak, aby extrahovali strukturu kódu z nezdokumentovaných zdrojových souborů.