Każdy typ w .NET ma pełną nazwę złożoną z przestrzeni nazw i nazwy typu: System.Console, System.Collections.Generic.List<T>, System.Text.StringBuilder. Przestrzenie nazw grupują powiązane typy i chronią nazwy przed konfliktami, dzięki czemu twoja własna klasa Order czy Timer może współistnieć z klasami z bibliotek. Dyrektywa using na początku pliku importuje przestrzeń nazw, żeby można było używać krótkich nazw.
Wynik:
Cart: tea, honey
1
Dyrektywa using wpływa tylko na nazwy w czasie kompilacji. Nie ładuje biblioteki ani nie dodaje kodu do programu; o tym, które biblioteki są dostępne, decydują referencje projektu i pakiety NuGet. Jeśli kompilator zgłasza, że typu lub przestrzeni nazw "could not be found (are you missing a using directive or an assembly reference?)", czyli błąd CS0246, to albo brakuje linii using, albo pakiet nie jest dołączony do projektu.
Deklarowanie własnych przestrzeni nazw
Umieść typy w bloku namespace. Przestrzenie nazw można zagnieżdżać i zapisywać z kropkami, a ta sama przestrzeń nazw może być rozłożona na wiele plików.
Wynik:
120.00 via DHL
Shop.Billing.Invoice
namespace Shop.Billing { } to skrót od namespace Shop { namespace Billing { } }. Kod wewnątrz Shop może odwołać się do Billing.Invoice bez prefiksu Shop., bo nazwy są najpierw wyszukiwane w otaczających przestrzeniach nazw.
Konwencje: zacznij od firmy lub produktu (Contoso.Payments), potem funkcja lub warstwa, i dopasuj to do struktury folderów (Contoso.Payments/Refunds/RefundService.cs zawiera Contoso.Payments.Refunds). Nigdy nie nazywaj klasy tak samo jak jej przestrzeń nazw (Shop.Shop), bo wymusza to niezgrabną kwalifikację wszędzie.
Aliasy
using Name = Namespace.Type; nadaje typowi (albo przestrzeni nazw) lokalną nazwę. Przydaje się to w dwóch sytuacjach: przy skracaniu długiego typu generycznego i przy rozwiązywaniu konfliktu.
Wynik:
latte: 3.60
order 17
Aliasy działają tylko w pliku, w którym je zadeklarowano (chyba że są global, o czym niżej). W C# 12 i nowszych alias może nazywać dowolny typ, także krotki i tablice: using Point = (int X, int Y);.
Niejednoznaczne odwołania (CS0104)
Gdy dwie zaimportowane przestrzenie nazw zawierają typ o tej samej nazwie, użycie krótkiej nazwy jest błędem. Klasyczny przypadek to Timer, który istnieje w System.Threading, System.Timers i (w aplikacjach desktopowych) System.Windows.Forms:
using System.Threading;
using System.Timers;
var t = new Timer(1000);
// error CS0104: 'Timer' is an ambiguous reference between
// 'System.Timers.Timer' and 'System.Threading.Timer'
Trzy rozwiązania, od najbardziej do najmniej lokalnego: napisz w pełni kwalifikowaną nazwę (new System.Timers.Timer(1000)), dodaj alias, który mówi, o który typ chodzi, albo usuń niepotrzebną dyrektywę.
Wynik:
250
System.Timers.Timer
System.Threading.Timer
Jeśli twoja własna przestrzeń nazw definiuje typ o nazwie System lub Console, prefiks global:: wymusza wyszukiwanie od korzenia: global::System.Console.WriteLine("hi");. Z tego powodu kod generowany używa go wszędzie.
using static
using static importuje statyczne składowe jednego typu, więc można je wywoływać bez nazwy typu. Pasuje do kodu, który wciąż wywołuje tę samą klasę, na przykład Math:
Wynik:
Area: 28.27
Hypotenuse: 5
42
using static działa też z enumami (using static System.DayOfWeek; pozwala pisać Monday) i z twoimi własnymi klasami statycznymi. Używaj go tam, gdzie krótkie nazwy pozostają jednoznaczne; samo WriteLine w dużym pliku może zostawić czytelnika z pytaniem, o jaki mechanizm zapisu chodzi.
global using i przestrzenie nazw o zasięgu pliku (C# 10)
Dwie funkcje C# 10 ograniczają powtarzalny kod na początku plików. Global using obowiązuje w każdym pliku projektu i zwykle trzyma się go w jednym pliku, na przykład GlobalUsings.cs:
// GlobalUsings.cs, C# 10 and later
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Money = System.Decimal;
Projekty SDK w .NET 6 i nowszych mogą generować je za ciebie. Z <ImplicitUsings>enable</ImplicitUsings> w pliku .csproj (domyślnie w nowych szablonach) projekt konsolowy dostaje System, System.Collections.Generic, System.IO, System.Linq, System.Net.Http, System.Threading i System.Threading.Tasks; projekty webowe dostają dodatkowo przestrzenie nazw ASP.NET Core. Dlatego nowoczesne pliki Program.cs zaczynają się od razu od kodu.
Przestrzeń nazw o zasięgu pliku (file-scoped namespace) deklaruje przestrzeń nazw dla całego pliku średnikiem zamiast bloku, oszczędzając jeden poziom wcięcia:
// C# 10 and later
namespace Shop.Billing;
public class Invoice
{
public decimal Amount { get; set; }
}
Plik może mieć tylko jedną przestrzeń nazw o zasięgu pliku i nie można jej mieszać z przestrzeniami blokowymi w tym samym pliku. Starsze projekty, skrypty Unity i kod pod .NET Framework używają formy blokowej pokazanej wcześniej.
Gdzie umieszczać dyrektywy using, a instrukcja using
Dyrektywy using muszą występować przed wszelkimi deklaracjami przestrzeni nazw lub typów w pliku (global using przed wszystkim innym). Można je też umieścić wewnątrz bloku przestrzeni nazw i wtedy obowiązują tylko tam; przewodniki stylu się różnią, a większość kodu .NET trzyma je na początku pliku.
Słowo kluczowe using ma wewnątrz metod drugie, niezwiązane zadanie: instrukcja using using (var file = File.OpenRead(path)) { ... } wywołuje Dispose na obiekcie, gdy blok się kończy, zamykając pliki i połączenia. Łączy je tylko słowo kluczowe. Zobacz stronę o instrukcji using.
Najczęściej zadawane pytania
Co robi using w C#?
Na początku pliku using System.Text; to dyrektywa, która importuje przestrzeń nazw, dzięki czemu możesz pisać StringBuilder zamiast System.Text.StringBuilder. Nie dodaje żadnego kodu i niczego nie ładuje; jedynie skraca nazwy. Wewnątrz metody using (var f = ...) to inna funkcja języka, instrukcja using, która zwalnia obiekt (Dispose) na końcu bloku.
Czym jest przestrzeń nazw w C#?
Przestrzeń nazw (namespace) to nazwana grupa typów, która zapobiega konfliktom nazw i porządkuje kod, na przykład System.Collections.Generic albo MyShop.Billing. Dwie klasy mogą mieć tę samą nazwę, jeśli są w różnych przestrzeniach nazw. Zgodnie z konwencją przestrzenie nazw odzwierciedlają strukturę folderów i zaczynają się od nazwy firmy lub produktu.
Czym jest using static w C#?
using static System.Math; importuje statyczne składowe jednego typu, więc możesz wywołać Sqrt(16) i odczytać PI bez prefiksu Math.. Działa z każdą klasą, także z twoimi własnymi i z enumami. Używaj go tam, gdzie krótkie nazwy pozostają jasne, na przykład w kodzie pełnym obliczeń matematycznych.
Jak naprawić błąd "is an ambiguous reference" w C#?
Błąd CS0104 oznacza, że dwie zaimportowane przestrzenie nazw zawierają typ o tej nazwie, na przykład Timer w System.Threading i System.Timers. Napisz w pełni kwalifikowaną nazwę (System.Timers.Timer), usuń jedną z dyrektyw using albo dodaj alias: using Timer = System.Timers.Timer;.
Czym jest global using w C#?
global using System.Text; (C# 10) importuje przestrzeń nazw dla każdego pliku w projekcie, a nie tylko dla tego, w którym się pojawia. Projekty SDK w .NET 6 i nowszych generują zestaw globalnych dyrektyw using automatycznie, gdy ustawione jest <ImplicitUsings>enable</ImplicitUsings>, i dlatego nowe pliki Program.cs nie mają żadnych linii using.