Globalne użycia w C# 10 i .NET 6 w 10 minut lub mniej
[[academy-video-youtube({"vid": "RWYrafpP53A", "start_time": "0", "title": "Global Usings in C# 10 and .NET 6 In 10 Minutes or Less", "creator": "Tim Corey", "length": "5m 33s"})]]
Każdy, kto przewinął na górę pliku C#, zna ceremonię: kolumna instrukcji using ustawiona powyżej każdej deklaracji klasy, powtarzająca się z jednego pliku do drugiego. Typowy projekt odwołuje się do tych samych garści przestrzeni nazw wielokrotnie, a edytowanie ich wszystkich, gdy trzeba coś w nich zmienić, to zadanie, które nie przynosi żadnych rzeczywistych korzyści. C# 10 dodało dyrektywę global using, aby usunąć to powtarzanie całoprojektowe.
W swoim filmie "Global Usings in C# 10 and .NET 6 In 10 Minutes or Less", Tim Corey omawia, co robią globalne usings, gdzie je umieścić, aby zespół mógł je znaleźć, oraz statyczną wariantę, która pozwala na pominięcie prefiksu klasy przy wywołaniu jej członków. Podkreśla także pułapkę projektową, którą warto mieć na uwadze: globalne importowanie przestrzeni nazw naraża cały projekt na nazwy dostępne w tej przestrzeni. Każdy, kto kopiował te same pięć linii using do każdej nowej klasy, znajdzie wzorzec oczyszczania tutaj.
Problem z powtarzaniem
[0:17 - 1:50] Tim zaczyna z nową aplikacją konsoli .NET 6 i tworzy folder Data zawierający klasę PersonModel. Odwołanie się do tej klasy z Program.cs wymaga dodania oczekiwanej linii using GlobalUsings.Data; na początku pliku. Dodanie drugiej klasy, która również potrzebuje PersonModel, oznacza dodanie tej samej linii using na początku tego pliku. Z pięćdziesięcioma klasami, ten sam import jest pisany pięćdziesiąt razy.
To jest dokładnie sytuacja, dla której zaprojektowano global using. Każda przestrzeń nazw, typ lub klasa statyczna, od której cały projekt zależy, może zostać zadeklarowana raz i udostępniona wszystkim plikom bez pojedynczego powtórzenia.
Promowanie instrukcji Using do zasięgu globalnego
[1:50 - 2:24] Składnia to jedno słowo kluczowe przed istniejącą dyrektywą:
global using GlobalUsings.Data;global using GlobalUsings.Data;Ta jedna linia, umieszczona w dowolnym pliku .cs w projekcie, sprawia, że GlobalUsings.Data jest dostępne we wszystkich innych plikach w tym samym projekcie. Pozostałe klasy, które wcześniej potrzebowały swojej własnej linii using dla PersonModel, już tego nie wymagają; typ rozwiązuje się automatycznie. Zasięg kończy się na granicy projektu, więc odwołanie do klas z sąsiedniego projektu wciąż wymaga normalnego odniesienia do projektu plus swojego własnego globalnego lub jednostkowego using.
To, czego to nie robi, to ukrywanie, skąd pochodzą typy. Kompilator nadal rozwiązuje PersonModel do jego przestrzeni nazw; przestrzeń nazw jest po prostu wstępnie importowana. Zachowanie w czasie wykonywania jest identyczne z napisaniem tego samego using na górze każdego pliku.
Centralizowanie usings w jednym pliku
[2:24 - 3:32] Rozpraszanie globalnych dyrektyw using po losowych plikach jest technicznie poprawne, ale praktycznie nieporządne. Jeśli nowy członek zespołu zobaczy, że PersonModel rozwiązuje się bez oczywistego importu, musi przeszukać projekt, aby znaleźć, gdzie zostało to globalnie zdefiniowane. Obecnie pojawiającą się konwencją jest utrzymywanie wszystkich globalnych usings w jednym pliku na korzeń projektu, nazwanym czymś przewidywalnym jak Usings.cs lub GlobalUsings.cs:
// Usings.cs at the project root
global using GlobalUsings.Data;
global using System.Text.Json;
global using System.Collections.Concurrent;// Usings.cs at the project root
global using GlobalUsings.Data;
global using System.Text.Json;
global using System.Collections.Concurrent;Plik nie zawiera nic poza tym. Każdy, kto dołącza do projektu, wie dokładnie, gdzie spojrzeć, aby zobaczyć, co jest dostępne globalnie. To schodzą się z przestrzeniami nazw opartymi na plikach i innymi funkcjami skracania ceremonii które pojawiły się w ostatnich wersjach C#, wszystkie mają na celu ułatwienie przeglądania projektu na pierwszy rzut oka.
Globalne użycie statyczne dla importowania metod
[3:32 - 4:50] Dyrektywa global using łączy się z formą użycia statycznego, która została dodana wcześniej. Połączenie umożliwia zrezygnowanie z prefiksu klasy dla statycznego członka klasy w całym projekcie. Przypadek motywujący, który pokazuje Tim, to Console.WriteLine:
global using static System.Console;global using static System.Console;Z tą pojedynczą linią w scentralizowanym pliku usings, Console.WriteLine("hello") staje się po prostu WriteLine("hello") w całym projekcie. Ten sam wzorzec działa dla pomocników matematycznych (globalne użycie static System.Math pozwala pisać Sqrt(x) bez prefiksu) oraz dla każdej innej klasy statycznej, na którą ciężko polega wasza baza kodu.
To jest forma, w której Tim jest najbardziej ostrożny. Pomijanie prefiksu klasy to zysk w czytelności, gdy metody są oczywiste, ale może być źródłem zamieszania, gdy dwie statyczne klasy udostępniają metody z tą samą nazwą. Czytelnik patrzący na czyste wywołanie WriteLine musi zaufać centralnemu plikowi zamiast widzieć źródło w kontekście.
Kiedy globalne importy zachodzą na siebie
[4:50 - 5:14] Cały sens przestrzeni nazw to utrzymanie typów o tej samej krótkiej nazwie, aby nie kolidowały. Globalne importowanie przestrzeni nazw usuwa ten bufor dla całego projektu jednocześnie. Jeśli wasza przestrzeń nazw GlobalUsings.Data zawiera klasę Data i również globalnie importujecie System.Data, każdy plik teraz musi rozstrzygać niejednoznaczności. Koszt pojawia się nie tam, gdzie występuje konflikt, ale w każdym przyszłym pliku, który będzie się wahał między dwoma.
Zaleceniem Tima jest używanie globalnych 'usings' celowo, preferowanie przestrzeni nazw, na których cały projekt się opiera, i być szczególnie ostrożnym z globalnym 'using static'. Rozsądny zestaw startowy to przestrzenie nazw, które każdy plik i tak importuje; rozszerzanie listy poza to wymaga przeglądu kodu.
Podsumowanie: Mniej ceremonii, to samo działanie
[5:14 - 5:33] Globalne 'usings' to niewielka funkcja, która przynosi korzyści przez cały czas trwania projektu. Każdy plik, który nie zawiera pięciu linii nadmiarowych importów, to plik, który otwiera się na rzeczywisty kod szybciej, a edycja wspólnej przestrzeni nazw odbywa się w jednym miejscu zamiast w dziesiątkach. Ta sama staranność, która wchodzi w aliasy typów i szerszą rodzinę usingów obowiązuje tutaj: używaj tam, gdzie wygrana w czytelności jest oczywista, i trzymaj scentralizowany plik na tyle mały, że kolejny programista może go przejrzeć jednym rzutem oka.
Wnioski
[5:14 - 5:33] Globalne 'usings' zastępują linie 'using' na plik z dyrektywami dla całego projektu, wariant globalnego 'using static' usuwa prefiks klasy z wywołań statycznych członków, a pojedynczy plik Usings.cs w katalogu głównym projektu to konwencja, która utrzymuje go odkrywalnym. Funkcja jest opcjonalna i dodająca, więc jej włączenie do istniejącej bazy kodu jest stopniowe.
Przykład porady: Kiedy włączacie ukryte usings przez <ImplicitUsings>enable</ImplicitUsings> w waszym .csproj, SDK automatycznie dodaje opracowany zestaw globalnych usings (jak System, System.Linq i System.Collections.Generic) bez ich pisania. Połącz to z własnym plikiem Usings.cs dla specyficznych dla projektu importów i góra każdego pliku staje się zauważalnie krótsza.
Oglądaj pełne wideo na jego kanale YouTube Channel i zyskaj więcej wglądu w nowoczesną strukturę projektu C# w serii 10-Minute Training.

