14 sposobów na uproszczenie kodu C# – Wglądy w najlepsze praktyki rozwijania C# z wideo Tima Coreya
W swoim obszernym filmie "14 sposobów na uproszczenie kodu C#" Tim Corey omawia praktyczne najlepsze praktyki C#, które poprawiają czytelność kodu, redukują bałagan i utrzymują bazę kodu w stanie łatwym do zarządzania. Zamiast obsesyjnie skupiać się na jednowierszowcach lub enigmatycznych sztuczkach, Tim koncentruje się na dobrych praktykach kodowania—jak pisać czysty, zrozumiały kod, który inni deweloperzy mogą śledzić.
Kazdy wskazowka opiera na rzeczywistych przykładach w Visual Studio, omawiajac konwencje nazewnictwa, obsługę błędów, a nawet jak refaktoryzowac kod, nie powodujac jego uszkodzenia. To nie tylko teoria – chodzi o to, że praktyka sprawia, iż kod jest lepszy.
W tym artykułe przejdziemy przez kazdy z 14 sposobow, które zaprezentowal.
1. Statyczne użycie dla czystszego kodu
Tim rozpoczyna od pokazania, jak statyczny dostep może uproscic powtarzajace wywolania. Poprzez zadeklarowanie:
using static System.Console;
using static System.Console;
nie musisz już poprzedzać każdego statycznego członka prefixem Console.
To nie tylko usuwanie slow—chodzi o uczynienie dostepu statycznego bardziej przejrzystym. Tim zwraca uwagę, że jeśli wywołujesz członka statycznego zdefiniowanego w często używanej klasie, takiej jak Console lub Math, to skrócenie poprawia czytelność kodu.
Jednak jako element dobrych praktyk programistycznych, ostrzega on, że programiści powinni unikać konfliktów — dwie różne klasy mogą mieć tę samą nazwę dla statycznego członka. Swiadomosc potencjalnego niespodziewanego zachowania jest kluczowa.
2. Inicjalizacja listy za pomocą
Teraz w C# można bezpośredniej inicjalizować listy:
List<string> names = ["Tim", "Sue", "Bilbo"];
List<string> names = ["Tim", "Sue", "Bilbo"];
Tim wyjaśnia, że nie chodzi o zmieszczenie wszystkiego w jednym stwierdzeniu, lecz o pisanie kodu, który jest łatwiejszy do czytania i optymalizacji wydajności poprzez redukcję ceremonii.
Zamiast analizować szablon "new List of String", czytelnik widzi dokładnie to, co jest istotne: opisowe nazwy w kolekcji. Tim zaznacza również, że działa to dla tablic, a nawet słowników, zgodnie z konwencjami kodowania, które priorytetem czynią przejrzystość.
3. Nowy o typie docelowym
Kolejne ułatwienie: target-typed new. Zamiast:
List<int> numbers = new List<int>();
List<int> numbers = new List<int>();
możesz pisać:
List<int> numbers = new();
List<int> numbers = new();
Tim podkreśla, że powtarzanie nazwy klasy jest niepotrzebne—już znajduje się po lewej stronie. Takie podejście zgodne jest z dobrymi praktykami programistycznymi poprzez usunięcie redundantności, co ułatwia przeglądanie kodu.
4. var i Typy Anonimowe
Tim zajmuje się var, funkcją, która wywołuje dyskusje w kręgach praktyk programistycznych. Niektorzy nie lubia tego, ze ukrywa nazwy zmiennych i typy, ale Tim wyjaśnia, ze jego prawdziwa sila tkwi w typach anonimowych.
Podczas pracy ze źródłami danych (takimi jak SQL za pomocą Dapper), Tim pokazuje, jak var pozwala tworzyć obiekty dynamicznie:
var parameters = new { FirstName = "Tim", LastName = "Corey" };
var parameters = new { FirstName = "Tim", LastName = "Corey" };
Jest to idealne do pisania zapytań lub jednorazowych obiektów—nie musisz tworzyć klasy bazowej tylko dla parametrów. Jak mówi Tim, to unika zanieczyszczania bazy kodu niepotrzebnymi typami, jednocześnie dostarczając znaczące komunikaty o błędach, jeśli coś pójdzie nie tak.
5. File-Scoped Namespaces
Tim przechodzi do przestrzeni nazw w zakresie pliku, pokazując, jak to:
namespace ProjectName
{
// indented code
}
namespace ProjectName
{
// indented code
}
staje się tym:
namespace ProjectName;
namespace ProjectName;
Ta drobna zmiana eliminuje niepotrzebne wcięcia i stosuje konwencje nazewnictwa w C# takie jak konwencja Pascal dla publicznych członków. Tim wyjaśnia, że ponieważ większość plików zawiera tylko jedno namespace, poprawia to czytelność kodu i utrzymuje logiczne sekcje w porządku.
6. Rekordy dla jednolinijkowych struktur danych
Użycie rekordów pozwala zdefiniować obiekty danych w jednym tylko wyrażeniu:
public record EmployeeRecord(int Id, string Name);
public record EmployeeRecord(int Id, string Name);
Tim zauważa, że to generuje pełny typ—właściwości, niezmienność i ToString()—przy minimalnym wysiłku. Jest jasne, że scenariusze klas pochodnych nadal wymagają użycia klas, ale gdy obiekt jest tylko do odczytu, rekordy przestrzegają zasady pojedynczej odpowiedziąlności, dobrze realizując jedno zadanie.
7. Dopasowywanie wzorców
Tim demonstruje, jak dopasowywanie wzorców pomaga w obsłudze wyjątków i bezpiecznym wykonywaniu porównań. Zamiast pisać rozwlekłe sprawdzanie typów, można je połączyć:
if (emp is EmployeeRecord e)
{
e.Id = 1;
}
if (emp is EmployeeRecord e)
{
e.Id = 1;
}
Ta pojedyncza linia sprawdza i rzutuje. Tim mowi, ze jest to zgodne z dobrymi praktykami kodowania—unikasz jednosylabowych nazw zmiennych jak x lub y, a zamiast tego nadajesz opisowe nazwy jak e. Jasne nazwy metod i zmiennych sprawiają, że kod jest łatwiejszy do utrzymania dla innych deweloperów.
8. Interpolacja ciągów
Aby tworzyć czytelne ciągi znaków, Tim demonstruje interpolację ciągów znaków:
$"The employee with ID {e.Id} is {e.Name}"
$"The employee with ID {e.Id} is {e.Name}"
Wskazuje, że to ułatwia tworzenie przejrzystych komunikatów o błędach i pisanie komentarzy. Zamiast skomplikówanego łączenia, można dosłownie napisać kod, który czyta się jak po angielsku—poprawiając jakość kodu i upraszczając przyszłe testy jednostkowe, które sprawdzają wynik.
9. nameof() dla bezpiecznego refaktoryzowania
Tim pokazuje, jak nameof() chroni cię podczas refaktoryzacji kodu. Nazwy zmiennych zakodowane na sztywno w ciągach znaków mogą prowadzić do nieoczekiwanego zachowania, jeśli zostaną zmienione. Ale pisząc:
nameof(emp)
nameof(emp)
kompilator automatycznie aktualizuje każde użycie. Jest to jedna z najlepszych praktyk, która utrzymuje baze kodu w dobrym stanie, gdy piszesz czysty i zorganizowany kod.
10. Krotki dla wielu wartości zwracanych
Zamiast tworzyć klasę bazową tylko po to, aby zwrócić dwie wartości, Tim używa krotek:
(string FirstName, string LastName) SplitName(string fullName)
(string FirstName, string LastName) SplitName(string fullName)
Unika to niepotrzebnych zewnętrznych zależności i przestrzega zasady pojedynczej odpowiedziąlności—metoda po prostu dzieli nazwę, nic więcej. Jak mówi Tim, praktyka czyni kod lepszym, kiedy unika się nadmiernego stosowania skomplikówanych rozwiązań.
11. Dekonstrukcja
Opierając się na krotkach, Tim pokazuje, jak zdekonstruować wyniki na lokalne zmienne:
var (firstName, lastName) = SplitName("Tim Corey");
var (firstName, lastName) = SplitName("Tim Corey");
To utrzymuje opisowe nazwy zmiennych i unika nieczytelnej składni krotek później. Tim nawet odnosi się do odrzucania nieużywanych wartości (używając _), co sygnalizuje zamierzenie—żadne jednoliterowe nazwy zmiennych nie pozostają niewyjaśnione.
12. Odrzucenie niepotrzebnych wartości
Jeśli nie potrzebujesz wszystkich części krotki, Tim zaleca przecinki:
var (firstName, _) = SplitName("Tim Corey");
var (firstName, _) = SplitName("Tim Corey");
To pokazuje innym programistom, że celowo ignorujesz wartość, co jest przydatne w ramach testowych lub testach jednostkowych, gdzie nie wszystkie wyniki są istotne.
13. Używanie instrukcji using bez bloków
Tim przechodzi do zarządzania zasobami i obsługi błędów. Wczesniej pisalbys:
using (var connection = new SqlConnection(connString))
{
// work
}
using (var connection = new SqlConnection(connString))
{
// work
}
Teraz możesz użyć:
using var connection = new SqlConnection(connString);
using var connection = new SqlConnection(connString);
To jest zgodne z zasadami SOLID—w szczególności z zasadą pojedynczej odpowiedziąlności i zasadą odwrócenia zależności. Tim zauważa, że ta składnia działa dobrze dla zewnętrznych zależności, takich jak bazy danych, zapewniając, że obsługa wyjątków jest bardziej przejrzysta, a połączenia są zawsze zamykane, co zapobiega problemom z wydajnością lub nawet scenariuszom injekcji SQL, gdy połączenia nie są usuwane.
14. Inlinowe deklaracje zmiennych wyjsciowych
Na koniec, Tim omawia deklaracje zmiennych inline out w kontekście takich rzeczy jak parsowanie:
if (int.TryParse(numberText, out int numberValue))
if (int.TryParse(numberText, out int numberValue))
Tutaj tworzysz zmienną lokalną w tej samej linii. Dzięki temu konwencje kodowania są ścisłe, a nazwy metod opisowe. Poprawne grupowanie kodu zmniejsza nieoczekiwane zachowania i sprawia, że przyszłe wysiłki związane z refaktoryzacją kodu są bezpieczniejsze.
Podsumowanie
Tim konczy swoje wideo przypominajac widzom: te uproszczenia nie są o pisaniu zagadkowych jednoliniowcow—chodzi o dobre praktyki programistyczne. Funkcje takie jak użycie elementów statycznych, rekordów, dopasowywania wzorców, krotek i ignorowanie wartości pozwalają pisać czysty, nowoczesny kod w C#.
Zachęca programistów do zastanowienia się nad konwencjami nazewnictwa, obsługą błędów i używaniem znaczących nazw podczas przyjmowania tych funkcji. "Kod ma być czytelny dla ludzi," mówi Tim—i kiedy piszesz kod, który jest łatwy do zrozumieniuiuiuiuia, ułatwiasz życie sobie oraz innym programistom.
Krotko mowiac: zastosuj sie do najlepszych praktyk C#, przestrzegaj zasad SOLID, takich jak zasada pojedynczej odpowiedziąlnosci, zasada segregacji interfejsow i zasada odwrocenia zależności, a twoj kod nie tylko sie skompiluje, ale także poprawi wydajność, zredukuje nieoczekiwane zachowanie i utrzyma zespol z zadowoleniem piszacym kod.
