Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym samouczku wykonasz istniejący przykład zorientowany na obiekt (z poprzedniego samouczka) i ulepszysz go za pomocą komentarzy do dokumentacji XML. Komentarze dokumentacji XML zawierają przydatne etykietki narzędziowe funkcji IntelliSense i mogą być częścią dokumentacji wygenerowanych interfejsów API. Dowiesz się, które elementy zasługują na komentarze, jak używać tagów podstawowych, takich jak <summary>, <param>, <returns>, <value>, <remarks>, <example>, <seealso>, <exception>, i <inheritdoc> oraz jak spójne, celowe komentowanie poprawia łatwość konserwacji kodu, umożliwia lepsze odnajdywanie informacji i ułatwia współpracę — bez generowania zbędnego szumu. Na koniec zanotowałeś publiczną powierzchnię przykładu, stworzyłeś projekt w celu wygenerowania pliku dokumentacji XML i zobaczyłeś, jak te komentarze przepływają bezpośrednio do środowiska dewelopera oraz oprogramowania dokumentacyjnego.
W tym samouczku nauczysz się następujących rzeczy:
- Włącz dane wyjściowe dokumentacji XML w projekcie języka C#.
- Dodaj i ustrukturyzuj komentarze dokumentacji XML dotyczące typów i członków.
- Skompiluj projekt i sprawdź wygenerowany plik dokumentacji XML.
Wymagania wstępne
- Zestaw SDK dla platformy .NET
- Program Visual Studio lub Visual Studio Code z zestawem deweloperskim języka C#.
Włączanie dokumentacji XML
Załaduj projekt utworzony w poprzednim samouczku zorientowanym na obiekt. Jeśli wolisz zacząć od nowa, sklonuj przykład z dotnet/docs repozytorium w folderze snippets/object-oriented-programming .
Następnie włącz dane wyjściowe dokumentacji XML, aby kompilator emitował plik .xml obok zespołu. Edytuj plik projektu i dodaj (lub potwierdź) następującą <PropertyGroup> właściwość wewnątrz elementu:
<GenerateDocumentationFile>True</GenerateDocumentationFile>
Jeśli używasz programu Visual Studio, możesz włączyć tę opcję przy użyciu strony właściwości "build".
Skompiluj projekt. Kompilator tworzy plik XML, który agreguje wszystkie /// komentarze z publicznie widocznych typów i elementów członkowskich. Ten plik zasila podpowiedzi IntelliSense, narzędzia do analizy statycznej oraz systemy generowania dokumentacji na późniejszych etapach.
Skompiluj teraz projekt. Zostaną wyświetlone ostrzeżenia dotyczące wszystkich publicznych członków, którzy nie mają <summary> komentarzy. Traktuj te ostrzeżenia jako zadania do wykonania, które pomagają zapewnić kompletną, celową dokumentację. Otwórz wygenerowany plik XML (obok danych wyjściowych kompilacji) i sprawdź początkową strukturę. Na początku sekcja jest pusta <members> , ponieważ nie dodano jeszcze komentarzy:
<?xml version="1.0"?>
<doc>
<assembly>
<name>oo-programming</name>
</assembly>
<members>
</members>
</doc>
Po uruchomieniu pliku rozpocznij dodawanie docelowych komentarzy XML i natychmiast sprawdź, jak każdy z nich pojawia się w wygenerowanych danych wyjściowych. Zacznij od typu rekordu 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);
Dodawanie komentarzy dokumentacji
Teraz przechodzisz przez ostrzeżenia kompilacji, aby dodać zwięzłą, przydatną dokumentację do BankAccount typu. Każde ostrzeżenie wskazuje publicznego członka, który nie ma <summary> (lub innego wymaganego) elementu. Traktuj listę ostrzeżeń jako listę kontrolną. Unikaj dodawania szumu: skup się na opisywaniu intencji, niezmiennych i ważnych ograniczeń użycia — pomiń ponowne określanie oczywistych nazw typów lub typów parametrów.
- Ponownie skompiluj projekt. W programie Visual Studio lub Visual Studio Code otwórz panel Lista błędów /Problemy i odfiltruj ostrzeżenia dokumentacji (CS1591). W wierszu polecenia uruchom kompilację i przejrzyj ostrzeżenia emitowane do konsoli.
- Przejdź do pierwszego ostrzeżenia (
BankAccountklasa). W wierszu powyżej deklaracji wpisz///. Edytor konstruuje element<summary>. Zastąp symbol zastępczy pojedynczym, skoncentrowanym na działaniu zdaniem. W zdaniu wyjaśniono rolę konta w domenie. Na przykład śledzi transakcje i wymusza minimalne saldo. - Dodaj
<remarks>tylko wtedy, gdy musisz wyjaśnić zachowanie. Przykłady obejmują, jak działa wymuszanie minimalnego salda lub jak generowane są numery kont. Zachowaj krótkie uwagi. - Dla każdej właściwości (
Number,Owner,Balance) wpisz///i napisz<summary>, która określa, co dana wartość reprezentuje — a nie jak trywialny getter ją zwraca. Jeśli właściwość oblicza wartość (na przykładBalance), dodaj<value>element, który wyjaśnia obliczenie. - Dla każdego konstruktora dodaj elementy
<summary>plus<param>, które opisują znaczenie każdego argumentu, a nie tylko powtarzają nazwę parametru. Jeśli jeden delegat przeciąża inny, dodaj zwięzły element<remarks>. - W przypadku metod, które mogą zgłaszać wyjątki, dodaj
<exception>tagi dla każdego celowego typu wyjątków. Opisz warunek, który go wyzwala. Nie dokumentuj wyjątków zgłaszanych przez pomocników weryfikacji argumentów, chyba że są częścią umowy publicznej. - W przypadku metod, które zwracają wartość, dodaj
<returns>i krótki opis tego, co otrzymują wywołujący. Unikaj powtarzania nazwy metody lub typu zarządzanego. - Najpierw pracuj z klasą bazową
BankAccount.
Twoja wersja powinna wyglądać podobnie do następującego kodu:
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() { }
}
Po zakończeniu otwórz ponownie wygenerowany plik XML i upewnij się, że każdy członek pojawi się z nowo dodanymi elementami. Przycięta część może wyglądać następująco:
<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>
Wskazówka
Zachowaj podsumowania do pojedynczego zdania. Jeśli potrzebujesz więcej niż jednego, przenieś kontekst pomocniczy do elementu <remarks>.
Używanie <inheritdoc/> w klasach pochodnych
Jeśli wywodzisz się z BankAccount (na przykład SavingsAccount, który nalicza odsetki), możesz dziedziczyć SavingsAccount podstawową dokumentację zamiast kopiować ją. Dodaj element samo zamykający <inheritdoc/> wewnątrz bloku dokumentacji pochodnego elementu członkowskiego. Możesz nadal dodawać więcej elementów (takich jak dodatkowe <remarks> szczegóły) po <inheritdoc/> w celu udokumentowania wyspecjalizowanego zachowania:
/// <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
Uwaga / Notatka
<inheritdoc/> zmniejsza duplikację i pomaga zachować spójność podczas aktualizowania dokumentacji typu podstawowego później.
Po zakończeniu dokumentowania publicznej powierzchni skompiluj jeden ostatni raz, aby potwierdzić, że nie ma żadnych pozostałych ostrzeżeń CS1591. Projekt tworzy teraz przydatną funkcję IntelliSense i ustrukturyzowany plik XML gotowy do publikowania przepływów pracy.
Pełny przykład z adnotacjami można zobaczyć w folderze źródłowym repozytorium dotnet/docs w witrynie GitHub.
Kompilowanie danych wyjściowych z komentarzy
Możesz odkrywać więcej, spróbuj użyć dowolnego z tych narzędzi, aby wygenerować dane wyjściowe z komentarzy XML.
- DocFX: DocFX to generator dokumentacji interfejsu API dla platformy .NET, który obecnie obsługuje języki C#, Visual Basic i F#. Umożliwia również dostosowanie wygenerowanej dokumentacji referencyjnej. DocFX tworzy statyczną witrynę internetową HTML z kodu źródłowego i plików Markdown. Ponadto rozwiązanie DocFX zapewnia elastyczność dostosowywania układu i stylu witryny internetowej za pomocą szablonów. Można również tworzyć szablony niestandardowe.
- Sandcastle: narzędzia Sandcastle tworzą pliki pomocy dla zarządzanych bibliotek klas zawierających zarówno strony referencyjne pojęć, jak i interfejsu API. Narzędzia Sandcastle są oparte na wierszu polecenia i nie mają frontonu graficznego interfejsu użytkownika, funkcji zarządzania projektami ani zautomatyzowanego procesu kompilacji. Narzędzie Sandcastle Help File Builder udostępnia autonomiczny graficzny interfejs użytkownika i narzędzia oparte na wierszach polecenia do tworzenia pliku pomocy w zautomatyzowany sposób. Dostępny jest również pakiet integracji programu Visual Studio, dzięki czemu projekty pomocy można tworzyć i zarządzać w całości z poziomu programu Visual Studio.
- Doxygen: Doxygen generuje przeglądarkę dokumentacji online (w języku HTML) lub podręcznik odwołania offline (w LaTeX) z zestawu udokumentowanych plików źródłowych. Istnieje również obsługa generowania wyników w formatach RTF (MS Word), PostScript, z linkami PDF, skompresowanych HTML, DocBook i stronach podręcznika Unix. Możesz skonfigurować narzędzie Doxygen, aby wyodrębnić strukturę kodu z nieudokumentowanych plików źródłowych.