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.
Napiwek
Dopiero zaczynasz programować oprogramowanie? Najpierw zacznij od samouczków Wprowadzenie . W miarę rozwoju projektów poznasz naturalnie organizację programów.
Czy masz doświadczenie w pracy w innym języku? Jeśli znasz rozwiązania i projekty w programie Visual Studio lub systemy kompilacji, takie jak Maven lub Cargo, ten artykuł mapuje te pojęcia na platformę .NET.
W miarę rozwoju aplikacji w języku C# musisz zorganizować kod. Platforma .NET udostępnia hierarchię narzędzi organizacyjnych — rozwiązań, projektów, zestawów, przestrzeni nazw i typów — które współpracują ze sobą, aby zapewnić możliwość zarządzania dużymi bazami kodu. Konwencje opisane tutaj reprezentują szeroki konsensus w społeczności platformy .NET. Możesz odejść z określonych powodów, ale przestrzeganie tych konwencji sprawia, że twój kod jest znany i nawigowalny dla innych deweloperów platformy .NET.
Hierarchia organizacyjna
Organizuj typową aplikację .NET w warstwach, od najszerszych do najbardziej specyficznych:
| Level | Opis | Przykład |
|---|---|---|
| Rozwiązanie | Kontener, który grupuje powiązane projekty. | MyApp.slnx |
| Projekt | Jednostka kompilacji, która tworzy jeden zestaw. | MyApp.Web.csproj |
| Zestawu | Kompilowany .dll lub .exe generowany przez projekt. |
MyApp.Web.dll |
| Namespace | Logiczne grupowanie typów. | MyApp.Web.Controllers |
| Typ | Klasa, struktura, interfejs, wyliczenie lub delegat. | OrderController |
Każdy poziom służy innego celu. Rozwiązania organizują przepływ pracy programowania. Projekty definiują, co jest kompilowane razem, a każdy projekt tworzy jeden zestaw. Zestawy są jednostką wdrażania i przechowywania wersji. Przestrzenie nazw uniemożliwiają kolizje nazw i ułatwiają znajdowanie typów. Pojedynczy zestaw może zawierać wiele przestrzeni nazw, a jedna przestrzeń nazw może obejmować wiele zestawów. Typy definiują rzeczywiste zachowanie i dane.
Projekty i zestawy
Każdy projekt kompiluje się w jeden zestaw: bibliotekę klas lub plik wykonywalny. Zacznij od pojedynczego projektu dla małych aplikacji — nie należy przedwcześnie dzielić. Głównym powodem utworzenia oddzielnego projektu jest ponowne użycie tego kodu w więcej niż jednej aplikacji. Poza ponownym użyciem dodaj projekty, gdy masz konkretny powód:
- Udostępnianie kodu między aplikacjami — wyodrębnianie udostępnionej logiki do biblioteki klas, do której odwołuje się wiele aplikacji.
- Oddzielne obawy — zapewnij niezależny dostęp do danych, logikę biznesową i warstwy prezentacji.
- Zależności sterujące — projekt może używać tylko typów z projektów, do których jawnie się odwołuje.
Pojedynczy projekt dobrze sprawdza się w przypadku wielu aplikacji. Oprzyj się pokusie tworzenia osobnych projektów „na wszelki wypadek.” Zawsze możesz wyodrębnić bibliotekę później, gdy druga aplikacja będzie potrzebować tego samego kodu.
Dopasowywanie przestrzeni nazw do struktury folderów
Nazwy przestrzeni nazw powinny odpowiadać strukturze folderów w Twoim projekcie. Gdy zostanie wyświetlona przestrzeń nazw MyApp.Services.Payments, musisz wyszukać w Services/Payments folderze kod źródłowy typów zdefiniowanych w tej przestrzeni nazw. Zestaw .NET SDK obsługuje tę konwencję, która jest tak szeroko stosowana, że jej naruszenie aktywnie dezorientuje innych deweloperów.
// File: Services/OrderService.cs
// Namespace mirrors the folder path
using MyApp.Core;
namespace MyApp.Services;
public class OrderService
{
public Order CreateOrder(string product, int quantity, decimal price) =>
new() { ProductName = product, Quantity = quantity, UnitPrice = price };
public string FormatSummary(Order order) =>
$"{order.Quantity}x {order.ProductName} = {order.Total:C}";
}
Główna przestrzeń nazw jest automatycznie ustawiana na nazwę pliku projektu. Typy w podfolderach nie są automatycznie przypisywane przestrzenie nazw podrzędnych — deklarujesz przestrzeń nazw jawnie w każdym pliku, ale zawsze utrzymuj je zsynchronizowane.
Napiwek
Przestrzeń nazw katalogu głównego można zmienić, ustawiając wartość <RootNamespace> w pliku projektu.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>MyCompany.MyApp</RootNamespace>
</PropertyGroup>
</Project>
Organizowanie przestrzeni nazw według funkcji, a nie według typu
Grupuj powiązane typy w przestrzenie nazw według funkcji lub odpowiedzialności. Umieść razem interfejs, jego implementacje i typy pomocnicze:
// Good: group by feature
namespace MyApp.Payments;
public interface IPaymentProcessor
{
bool ProcessPayment(decimal amount);
}
public class CreditCardProcessor : IPaymentProcessor
{
public bool ProcessPayment(decimal amount)
{
Console.WriteLine($"Processing credit card payment of {amount:C}");
return true;
}
}
public record PaymentResult(bool Success, string? TransactionId);
Organizacja oparta na funkcjach przechowuje wszystko, czego potrzebujesz w jednym miejscu, dzięki czemu kod jest łatwiejszy do nawigowania i rozumowania.
Modyfikatory dostępu i moduły
Modyfikatory dostępu współpracują ze strukturą projektu i zestawu w celu kontrolowania dostępności:
-
public— dostępny z dowolnego zestawu, który odwołuje się do tego zestawu. -
internal— dostępny tylko w ramach tego samego zestawu (ustawienie domyślne dla typów najwyższego poziomu). -
private,protected,private protected,protected internal— są dostępne w zależności od typu zawierającego, modułu lub typów pochodnych.
internal Ustawienie domyślne dla typów, których nie potrzebują inne projekty. Ta praktyka ukrywa szczegóły implementacji i zapewnia swobodę refaktoryzacji bez przerywania pracy użytkowników. Jest to szczególnie ważne w przypadku bibliotek udostępnionych:
namespace MyApp.Inventory;
// Public — other projects can use this type
public class InventoryService
{
public int GetStockLevel(string productName) =>
StockDatabase.Lookup(productName);
}
// Internal — only visible within this assembly
internal static class StockDatabase
{
private static readonly Dictionary<string, int> _stock = new()
{
["Widget"] = 42,
["Gadget"] = 17
};
internal static int Lookup(string productName) =>
_stock.GetValueOrDefault(productName);
}
Zalecane wskazówki
- Nazywaj przestrzenie nazw spójnie. Użyj
CompanyName.ProductName.Featurejako wzorca nazewnictwa. Użyj na przykład nazwyContoso.Inventory.Shipping. Spójne nazewnictwo ułatwia deweloperom znajdowanie typów bez wyszukiwania. - Zachowaj koncentrację projektów. Każdy projekt powinien mieć jedną, wyraźną odpowiedzialność. Gdy projekt obsługuje zbyt wiele niepowiązanych problemów, podziel go.
- Użyj przestrzeni nazw o zakresie plików. Składnia
namespace MyApp.Services;zmniejsza wcięcie i jest zalecanym stylem. Użyj go we wszystkich nowych kodach. - Domyślnie
internal. Oznaczaj typypublicjedynie wtedy, gdy inne zespoły faktycznie ich potrzebują. Zawsze możesz poszerzyć dostęp później; zawężenie jest zmianą powodującą niezgodność.