Typowe konwencje kodu języka C#

Standard kodu jest niezbędny do utrzymania czytelności kodu, spójności i współpracy w zespole deweloperów. Kod zgodny z praktykami branżowymi i ustalonymi wytycznymi jest łatwiejszy do zrozumienia, utrzymania i rozszerzania. Większość projektów wymusza spójny styl za pomocą konwencji kodu. Projekty dotnet/docs i dotnet/samples nie są wyjątkiem. W tej serii artykułów poznasz nasze konwencje kodowania i narzędzia, których używamy do ich wymuszania. Możesz podjąć nasze konwencje zgodnie z oczekiwaniami lub zmodyfikować je zgodnie z potrzebami twojego zespołu.

Wybraliśmy nasze konwencje na podstawie następujących celów:

  1. Poprawność: nasze przykłady są kopiowane i wklejane do aplikacji. Oczekujemy, że dlatego musimy zrobić kod, który jest odporny i poprawny, nawet po wielu edycjach.
  2. Nauczanie: Celem naszych przykładów jest nauczenie wszystkich platform .NET i C#. Z tego powodu nie nakładamy ograniczeń dotyczących żadnej funkcji językowej ani interfejsu API. Zamiast tego te przykłady uczą się, gdy funkcja jest dobrym wyborem.
  3. Spójność: Czytelnicy oczekują spójnego środowiska w naszej zawartości. Wszystkie próbki powinny być zgodne z tym samym stylem.
  4. Wdrażanie: agresywnie aktualizujemy nasze przykłady, aby korzystały z nowych funkcji językowych. Ta praktyka zwiększa świadomość nowych funkcji i sprawia, że są bardziej znane wszystkim deweloperom języka C#.

Ważne

Te wytyczne są używane przez firmę Microsoft do opracowywania przykładów i dokumentacji. Zostały one przyjęte z wytycznych dotyczących środowiska uruchomieniowego .NET, stylu kodowania w języku C# i kompilatora języka C# (roslyn). Wybraliśmy te wytyczne, ponieważ zostały przetestowane w ciągu kilku lat opracowywania rozwiązań typu open source. Pomogli członkom społeczności uczestniczyć w projektach środowiska uruchomieniowego i kompilatora. Są one przeznaczone do bycia przykładem typowych konwencji języka C#, a nie listy autorytatywnej (zobacz Wytyczne dotyczące projektowania struktury).

Cele nauczania i wdrażania są powodem, dla których konwencja kodowania dokumentów różni się od konwencji środowiska uruchomieniowego i kompilatora. Zarówno środowisko uruchomieniowe, jak i kompilator mają ścisłe metryki wydajności dla ścieżek gorących. Wiele innych aplikacji nie. Nasz cel nauczania nakazuje, że nie zabraniamy żadnej konstrukcji. Zamiast tego przykłady pokazują, kiedy należy używać konstrukcji. Aktualizujemy próbki bardziej agresywnie niż większość aplikacji produkcyjnych. Nasz cel wdrożenia nakazuje pokazanie kodu, który należy napisać dzisiaj, nawet jeśli kod napisany w zeszłym roku nie wymaga zmian.

W tym artykule wyjaśniono nasze wytyczne. Wytyczne ewoluowały wraz z upływem czasu i znajdziesz przykłady, które nie są zgodne z naszymi wytycznymi. Z zadowoleniem przyjmujemy żądania ściągnięcia, które zapewniają zgodność tych przykładów lub problemy, które zwracają uwagę na próbki, które należy zaktualizować. Nasze wytyczne to open source i mile widziane żądania ściągnięcia i problemy. Jeśli jednak twoje przesłanie zmieni te zalecenia, najpierw otwórz problem do dyskusji. Zachęcamy do korzystania z naszych wytycznych lub dostosowania ich do Twoich potrzeb.

Narzędzia i analizatory

Narzędzia mogą pomóc zespołowi w wymuszaniu standardów. Możesz włączyć analizę kodu, aby wymusić preferowane reguły. Możesz również utworzyć konfigurację edytora, aby program Visual Studio automatycznie wymuszał wytyczne dotyczące stylu. Jako punkt wyjścia możesz skopiować plik repozytorium dotnet/docs, aby użyć naszego stylu.

Te narzędzia ułatwiają zespołowi przyjęcie preferowanych wytycznych. Program Visual Studio stosuje reguły we wszystkich .editorconfig plikach w zakresie do formatowania kodu. Można użyć wielu konfiguracji, aby wymusić standardy dla całej firmy, standardy zespołu, a nawet szczegółowe standardy projektu.

Analiza kodu generuje ostrzeżenia i diagnostykę, gdy włączone reguły zostaną naruszone. Skonfiguruj reguły, które chcesz zastosować do projektu. Następnie każda kompilacja ciągłej integracji powiadamia deweloperów, gdy naruszają one dowolne reguły.

Identyfikatory diagnostyczne

Wskazówki dotyczące języka

W poniższych sekcjach opisano praktyki, które zespół dokumentacji platformy .NET wykonuje w celu przygotowania przykładów i przykładów kodu. Ogólnie rzecz biorąc, postępuj zgodnie z następującymi rozwiązaniami:

  • Korzystaj z nowoczesnych funkcji językowych i wersji języka C#, jeśli to możliwe.
  • Unikaj przestarzałych lub przestarzałych konstrukcji językowych.
  • Przechwytuj tylko wyjątki, które mogą być prawidłowo obsługiwane; unikaj przechwytywania wyjątków ogólnych.
  • Użyj określonych typów wyjątków, aby zapewnić znaczące komunikaty o błędach.
  • Użyj zapytań LINQ i metod do manipulowania kolekcją, aby zwiększyć czytelność kodu.
  • Używanie programowania asynchronicznego z asynchronicznym i oczekiwaniem na operacje związane z operacjami we/wy.
  • Zachowaj ostrożność w przypadku zakleszczeń i używaj Task.ConfigureAwait , jeśli jest to konieczne.
  • Użyj słów kluczowych języka dla typów danych zamiast typów środowiska uruchomieniowego. Na przykład użyj polecenia string zamiast System.String, lub int zamiast System.Int32.
  • Użyj int zamiast niepodpisanych typów. Korzystanie z programu int jest powszechne w języku C#i jest łatwiejsze do interakcji z innymi bibliotekami w przypadku korzystania z programu int. Wyjątki dotyczą dokumentacji specyficznej dla niepodpisanych typów danych.
  • Użyj var tylko wtedy, gdy czytelnik może wywnioskować typ z wyrażenia. Czytelnicy wyświetlają nasze przykłady na platformie docs. Nie mają one wskaźnika myszy ani wskazówek narzędzi, które wyświetlają typ zmiennych.
  • Napisz kod z jasnością i prostotą.
  • Unikaj nadmiernie złożonej i splotowej logiki kodu.

Postępuj zgodnie z bardziej szczegółowymi wytycznymi.

Dane ciągu

  • Użyj interpolacji ciągów, aby połączyć krótkie ciągi, jak pokazano w poniższym kodzie.

    string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
    
  • Aby dołączyć ciągi w pętlach, szczególnie podczas pracy z dużą ilością tekstu, użyj System.Text.StringBuilder obiektu.

    var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
    var manyPhrases = new StringBuilder();
    for (var i = 0; i < 10000; i++)
    {
        manyPhrases.Append(phrase);
    }
    //Console.WriteLine("tra" + manyPhrases);
    

Tablice

  • Użyj zwięzłej składni podczas inicjowania tablic w wierszu deklaracji. W poniższym przykładzie nie można użyć funkcji var zamiast string[].
string[] vowels1 = { "a", "e", "i", "o", "u" };
  • Jeśli używasz jawnego wystąpienia, możesz użyć polecenia var.
var vowels2 = new string[] { "a", "e", "i", "o", "u" };

Delegaci

  • Użyj poleceń Func<> i Action<> zamiast definiować typy delegatów. W klasie zdefiniuj metodę delegata.
Action<string> actionExample1 = x => Console.WriteLine($"x is: {x}");

Action<string, string> actionExample2 = (x, y) =>
    Console.WriteLine($"x is: {x}, y is {y}");

Func<string, int> funcExample1 = x => Convert.ToInt32(x);

Func<int, int, int> funcExample2 = (x, y) => x + y;
  • Wywołaj metodę przy użyciu podpisu zdefiniowanego przez delegata Func<> lub Action<> .
actionExample1("string for x");

actionExample2("string for x", "string for y");

Console.WriteLine($"The value is {funcExample1("1")}");

Console.WriteLine($"The sum is {funcExample2(1, 2)}");
  • Jeśli tworzysz wystąpienia typu delegata, użyj zwięzłej składni. W klasie zdefiniuj typ delegata i metodę, która ma zgodny podpis.

    public delegate void Del(string message);
    
    public static void DelMethod(string str)
    {
        Console.WriteLine("DelMethod argument: {0}", str);
    }
    
  • Utwórz wystąpienie typu delegata i wywołaj je. Poniższa deklaracja przedstawia skondensowaną składnię.

    Del exampleDel2 = DelMethod;
    exampleDel2("Hey");
    
  • Poniższa deklaracja używa pełnej składni.

    Del exampleDel1 = new Del(DelMethod);
    exampleDel1("Hey");
    

try-catch instrukcje i using w obsłudze wyjątków

  • W przypadku większości obsługi wyjątków użyj instrukcji try-catch.

    static double ComputeDistance(double x1, double y1, double x2, double y2)
    {
        try
        {
            return Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
        }
        catch (System.ArithmeticException ex)
        {
            Console.WriteLine($"Arithmetic overflow or underflow: {ex}");
            throw;
        }
    }
    
  • Uprość kod przy użyciu instrukcji języka C#. Jeśli masz instrukcję try-finally , w której jedynym kodem w finally bloku jest wywołanie Dispose metody, użyj instrukcji using .

    W poniższym przykładzie instrukcja try-finally wywołuje Dispose tylko w finally bloku.

    Font bodyStyle = new Font("Arial", 10.0f);
    try
    {
        byte charset = bodyStyle.GdiCharSet;
    }
    finally
    {
        if (bodyStyle != null)
        {
            ((IDisposable)bodyStyle).Dispose();
        }
    }
    

    Tę samą czynność można wykonać za pomocą instrukcji using .

    using (Font arial = new Font("Arial", 10.0f))
    {
        byte charset2 = arial.GdiCharSet;
    }
    

    Użyj nowej using składni , która nie wymaga nawiasów klamrowych:

    using Font normalStyle = new Font("Arial", 10.0f);
    byte charset3 = normalStyle.GdiCharSet;
    

&&operatory i ||

  • Użyj && wartości zamiast & i || zamiast | podczas przeprowadzania porównań, jak pokazano w poniższym przykładzie.

    Console.Write("Enter a dividend: ");
    int dividend = Convert.ToInt32(Console.ReadLine());
    
    Console.Write("Enter a divisor: ");
    int divisor = Convert.ToInt32(Console.ReadLine());
    
    if ((divisor != 0) && (dividend / divisor) is var result)
    {
        Console.WriteLine("Quotient: {0}", result);
    }
    else
    {
        Console.WriteLine("Attempted division by 0 ends up here.");
    }
    

Jeśli dzielnika ma wartość 0, druga klauzula w instrukcji if spowoduje błąd czasu wykonywania. Jednak skróty operatorów &&, gdy pierwsze wyrażenie jest fałszywe. Oznacza to, że nie oblicza drugiego wyrażenia. Operator & oceni oba, co spowoduje błąd czasu wykonywania, gdy divisor ma wartość 0.

new Operator

  • Użyj jednej z zwięzłych form tworzenia wystąpienia obiektu, jak pokazano w poniższych deklaracjach.

    var firstExample = new ExampleClass();
    
    ExampleClass instance2 = new();
    

    Powyższe deklaracje są równoważne następującej deklaracji.

    ExampleClass secondExample = new ExampleClass();
    
  • Użyj inicjatorów obiektów, aby uprościć tworzenie obiektów, jak pokazano w poniższym przykładzie.

    var thirdExample = new ExampleClass { Name = "Desktop", ID = 37414,
        Location = "Redmond", Age = 2.3 };
    

    Poniższy przykład ustawia te same właściwości co w poprzednim przykładzie, ale nie używa inicjatorów.

    var fourthExample = new ExampleClass();
    fourthExample.Name = "Desktop";
    fourthExample.ID = 37414;
    fourthExample.Location = "Redmond";
    fourthExample.Age = 2.3;
    

Obsługa zdarzeń

  • Użyj wyrażenia lambda, aby zdefiniować procedurę obsługi zdarzeń, której nie trzeba usuwać później:
public Form2()
{
    this.Click += (s, e) =>
        {
            MessageBox.Show(
                ((MouseEventArgs)e).Location.ToString());
        };
}

Wyrażenie lambda skraca następującą tradycyjną definicję.

public Form1()
{
    this.Click += new EventHandler(Form1_Click);
}

void Form1_Click(object? sender, EventArgs e)
{
    MessageBox.Show(((MouseEventArgs)e).Location.ToString());
}

Statyczne elementy członkowskie

Wywołaj statyczne elementy członkowskie przy użyciu nazwy klasy ClassName.StaticMember. Dzięki temu kod jest bardziej czytelny, dzięki czemu dostęp statyczny jest przejrzysty. Nie należy kwalifikować statycznej składowej zdefiniowanej w klasie bazowej o nazwie klasy pochodnej. Podczas kompilowania tego kodu czytelność kodu jest myląca, a kod może ulec awarii w przyszłości, jeśli dodasz statyczny element członkowski o tej samej nazwie do klasy pochodnej.

zapytania LINQ

  • Użyj znaczących nazw zmiennych kwerendy. W poniższym przykładzie użyto seattleCustomers klientów, którzy znajdują się w Seattle.

    var seattleCustomers = from customer in customers
                           where customer.City == "Seattle"
                           select customer.Name;
    
  • Użyj aliasów, aby upewnić się, że nazwy właściwości typów anonimowych są poprawnie wielkich liter przy użyciu liter Pascal.

    var localDistributors =
        from customer in customers
        join distributor in distributors on customer.City equals distributor.City
        select new { Customer = customer, Distributor = distributor };
    
  • Zmień nazwę właściwości, gdy nazwy właściwości w wyniku będą niejednoznaczne. Jeśli na przykład zapytanie zwraca nazwę klienta i identyfikator dystrybutora, zamiast pozostawiać je jako Name i ID w wyniku, zmień ich nazwę, aby wyjaśnić, że Name jest to nazwa klienta i ID jest identyfikatorem dystrybutora.

    var localDistributors2 =
        from customer in customers
        join distributor in distributors on customer.City equals distributor.City
        select new { CustomerName = customer.Name, DistributorID = distributor.ID };
    
  • Użyj niejawnego pisania w deklaracji zmiennych zapytania i zmiennych zakresu. Te wskazówki dotyczące niejawnego wpisywania w zapytaniach LINQ zastępują ogólne reguły niejawnie typizowane zmiennych lokalnych. Zapytania LINQ często używają projekcji, które tworzą typy anonimowe. Inne wyrażenia zapytania tworzą wyniki z zagnieżdżonym typami ogólnymi. Niejawne zmienne typizowane są często bardziej czytelne.

    var seattleCustomers = from customer in customers
                           where customer.City == "Seattle"
                           select customer.Name;
    
  • Wyrównaj klauzule zapytania do klauzuli from , jak pokazano w poprzednich przykładach.

  • Użyj where klauzul przed innymi klauzulami zapytania, aby upewnić się, że późniejsze klauzule zapytania działają na zredukowanym, filtrowanym zestawie danych.

    var seattleCustomers2 = from customer in customers
                            where customer.City == "Seattle"
                            orderby customer.Name
                            select customer;
    
  • Użyj wielu from klauzul zamiast join klauzuli , aby uzyskać dostęp do kolekcji wewnętrznych. Na przykład kolekcja Student obiektów może zawierać kolekcję wyników testów. Po wykonaniu następującego zapytania zwraca on każdy wynik powyżej 90, wraz z nazwiskiem ucznia, który otrzymał wynik.

    var scoreQuery = from student in students
                     from score in student.Scores!
                     where score > 90
                     select new { Last = student.LastName, score };
    

Niejawnie typizowane zmienne lokalne

  • Użyj niejawnego wpisywania zmiennych lokalnych, gdy typ zmiennej jest oczywisty z prawej strony przypisania.

    var message = "This is clearly a string.";
    var currentTemperature = 27;
    
  • Nie używaj wartości var , gdy typ nie jest widoczny po prawej stronie przypisania. Nie zakładaj, że typ jest jasny z nazwy metody. Typ zmiennej jest uznawany za jasny, jeśli jest new to operator, jawne rzutowanie lub przypisanie do wartości literału.

    int numberOfIterations = Convert.ToInt32(Console.ReadLine());
    int currentMaximum = ExampleClass.ResultSoFar();
    
  • Nie używaj nazw zmiennych do określania typu zmiennej. To może nie być poprawne. Zamiast tego użyj typu, aby określić typ, i użyj nazwy zmiennej, aby wskazać informacje semantyczne zmiennej. Poniższy przykład powinien być używany string dla typu i coś podobnego iterations do wskazania znaczenia informacji odczytanych z konsoli.

    var inputInt = Console.ReadLine();
    Console.WriteLine(inputInt);
    
  • Unikaj używania var zamiast dynamicznego. Użyj dynamic polecenia , jeśli chcesz wnioskować o typie czasu wykonywania. Aby uzyskać więcej informacji, zobacz Using type dynamic (Przewodnik programowania w języku C#).

  • Użyj niejawnego pisania dla zmiennej pętli w for pętlach.

    W poniższym przykładzie użyto niejawnego pisania w instrukcji for .

    var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
    var manyPhrases = new StringBuilder();
    for (var i = 0; i < 10000; i++)
    {
        manyPhrases.Append(phrase);
    }
    //Console.WriteLine("tra" + manyPhrases);
    
  • Nie używaj niejawnego pisania, aby określić typ zmiennej pętli w foreach pętlach. W większości przypadków typ elementów w kolekcji nie jest natychmiast oczywisty. Nazwa kolekcji nie powinna polegać wyłącznie na wnioskowaniu typu jej elementów.

    W poniższym przykładzie użyto jawnego wpisywania w instrukcji foreach .

    foreach (char ch in laugh)
    {
        if (ch == 'h')
            Console.Write("H");
        else
            Console.Write(ch);
    }
    Console.WriteLine();
    
  • użyj typu niejawnego dla sekwencji wyników w zapytaniach LINQ. W sekcji linQ wyjaśniono, że wiele zapytań LINQ powoduje anonimowe typy, w których należy używać typów niejawnych. Inne zapytania powodują zagnieżdżone typy ogólne, w których var jest bardziej czytelny.

    Uwaga

    Należy zachować ostrożność, aby przypadkowo zmienić typ elementu iterowalnej kolekcji. Na przykład łatwo jest przełączyć się z System.Linq.IQueryable do System.Collections.IEnumerable w instrukcji foreach , która zmienia wykonywanie zapytania.

Niektóre z naszych przykładów wyjaśniają naturalny typ wyrażenia. Te przykłady muszą być używane var , aby kompilator wybierał typ naturalny. Mimo że te przykłady są mniej oczywiste, użycie metody var jest wymagane dla próbki. Tekst powinien wyjaśnić zachowanie.

Umieść dyrektywy using poza deklaracją przestrzeni nazw

using Gdy dyrektywa znajduje się poza deklaracją przestrzeni nazw, zaimportowana przestrzeń nazw jest w pełni kwalifikowaną nazwą. W pełni kwalifikowana nazwa jest jaśniejsza. using Gdy dyrektywa znajduje się wewnątrz przestrzeni nazw, może być względna względem tej przestrzeni nazw lub jej w pełni kwalifikowana nazwa.

using Azure;

namespace CoolStuff.AwesomeFeature
{
    public class Awesome
    {
        public void Stuff()
        {
            WaitUntil wait = WaitUntil.Completed;
            // ...
        }
    }
}

Zakładając, że istnieje odwołanie (bezpośrednie lub pośrednie) do WaitUntil klasy.

Teraz zmieńmy to nieco:

namespace CoolStuff.AwesomeFeature
{
    using Azure;

    public class Awesome
    {
        public void Stuff()
        {
            WaitUntil wait = WaitUntil.Completed;
            // ...
        }
    }
}

I kompiluje się dzisiaj. A jutro. Jednak czasami w przyszłym tygodniu poprzedni kod (nietknięty) kończy się niepowodzeniem z dwoma błędami:

- error CS0246: The type or namespace name 'WaitUntil' could not be found (are you missing a using directive or an assembly reference?)
- error CS0103: The name 'WaitUntil' does not exist in the current context

Jedna z zależności wprowadziła tę klasę w przestrzeni nazw, a następnie kończy się ciągiem .Azure:

namespace CoolStuff.Azure
{
    public class SecretsManagement
    {
        public string FetchFromKeyVault(string vaultId, string secretId) { return null; }
    }
}

Dyrektywa umieszczona using wewnątrz przestrzeni nazw jest wrażliwa na kontekst i komplikuje rozpoznawanie nazw. W tym przykładzie jest to pierwsza przestrzeń nazw, którą znajduje.

  • CoolStuff.AwesomeFeature.Azure
  • CoolStuff.Azure
  • Azure

Dodanie nowej przestrzeni nazw zgodnej CoolStuff.Azure z przestrzeń nazw lub CoolStuff.AwesomeFeature.Azure będzie zgodna z globalną Azure przestrzenią nazw. Można go rozwiązać, dodając global:: modyfikator do deklaracji using . Jednak łatwiej jest umieścić using deklaracje poza przestrzenią nazw.

namespace CoolStuff.AwesomeFeature
{
    using global::Azure;

    public class Awesome
    {
        public void Stuff()
        {
            WaitUntil wait = WaitUntil.Completed;
            // ...
        }
    }
}

Wskazówki dotyczące stylu

Ogólnie rzecz biorąc, użyj następującego formatu dla przykładów kodu:

  • Użyj czterech spacji do wcięcia. Nie używaj kart.
  • Spójne dopasowywanie kodu w celu zwiększenia czytelności.
  • Ogranicz wiersze do 65 znaków, aby zwiększyć czytelność kodu w dokumentacji, zwłaszcza na ekranach mobilnych.
  • Podziel długie instrukcje na wiele wierszy, aby zwiększyć przejrzystość.
  • Użyj stylu "Allman" dla nawiasów klamrowych: otwórz i zamyka nawias klamrowy własnego nowego wiersza. Nawiasy klamrowe są wyrównane z bieżącym poziomem wcięcia.
  • Podziały wierszy powinny występować przed operatorami binarnymi, jeśli to konieczne.

Styl komentarza

  • W celu uzyskania krótkich wyjaśnień użyj komentarzy jednowierszowych (//).

  • Unikaj komentarzy wielowierszowych (/* */) w celu uzyskania dłuższych wyjaśnień. Komentarze nie są zlokalizowane. Zamiast tego dłuższe wyjaśnienia znajdują się w artykule towarzyszącym.

  • Do opisywania metod, klas, pól i wszystkich publicznych elementów członkowskich należy używać komentarzy XML.

  • Umieść komentarz w osobnym wierszu, a nie na końcu wiersza kodu.

  • Rozpocznij tekst komentarza z wielką literą.

  • Zakończ tekst komentarza kropką.

  • Wstaw jedną spację między ogranicznikiem komentarza (//) i tekstem komentarza, jak pokazano w poniższym przykładzie.

    // The following declaration creates a query. It does not run
    // the query.
    

Konwencje układu

Dobry układ używa formatowania, aby podkreślić strukturę kodu i ułatwić odczytywanie kodu. Przykłady i przykłady firmy Microsoft są zgodne z następującymi konwencjami:

  • Użyj domyślnych ustawień Edytora kodu (inteligentne wcięcia, wcięcia czteroznakowe, karty zapisane jako spacje). Aby uzyskać więcej informacji, zobacz Opcje, Edytor tekstu, C#, Formatowanie.

  • Napisz tylko jedną instrukcję na wiersz.

  • Napisz tylko jedną deklarację na wiersz.

  • Jeśli wiersze kontynuacji nie są automatycznie wcięte, wcięcie ich do jednego zatrzymania karty (cztery spacje).

  • Dodaj co najmniej jedną pustą linię między definicjami metod i definicjami właściwości.

  • Użyj nawiasów, aby tworzyć klauzule w wyrażeniu widocznym, jak pokazano w poniższym kodzie.

    if ((startX > endX) && (startX > previousX))
    {
        // Take appropriate action.
    }
    

Wyjątki są wtedy, gdy przykład objaśnia pierwszeństwo operatora lub wyrażenia.

Zabezpieczenia

Postępuj zgodnie z wytycznymi w temacie Wytyczne dotyczące bezpiecznego kodowania.