Przewodnik po języku C#

C# (wymawiany jako "See Sharp") to nowoczesny, zorientowany obiektowo i bezpieczny pod typem język programowania. Język C# umożliwia deweloperom tworzenie wielu typów bezpiecznych i niezawodnych aplikacji uruchamianych na .NET. Język C# ma swoje korzenie w rodzinie języków C i od razu będzie zaznajomiony z programistami języków C, C++, Java i JavaScript. Ten przewodnik zawiera omówienie głównych składników języka w języku C# 8 i starszych. Jeśli chcesz poznać język za pomocą interaktywnych przykładów, wypróbuj wprowadzenie do samouczków języka C #.

C# to obiektowy, zorientowany na składniki język programowania. Język C# udostępnia konstrukcje językowe, które bezpośrednio obsługują te koncepcje, dzięki czemu język C# jest językiem naturalnym, w którym można tworzyć składniki oprogramowania i ich używać. Od czasu jego pochodzenia język C# dodał funkcje do obsługi nowych obciążeń i nowych rozwiązań w zakresie projektowania oprogramowania. W jego ramach C# jest językiem zorientowanym obiektowo . Definiujesz typy i ich zachowanie.

Kilka funkcji języka C# pomaga tworzyć niezawodne i trwałe aplikacje. Odzyskiwanie pamięci automatycznie odzyskuje pamięć zajętą przez nieosiągalne nieużywane obiekty. Typy dopuszczane wartością null chronią przed zmiennymi, które nie odwołują się do przydzielonych obiektów. Obsługa wyjątków zapewnia ustrukturyzowane i rozszerzalne podejście do wykrywania i odzyskiwania błędów. Wyrażenia lambda obsługują techniki programowania funkcjonalnego. Składnia zapytań LANGUAGE Integrated Query (LINQ) tworzy wspólny wzorzec pracy z danymi z dowolnego źródła. Obsługa języka dla operacji asynchronicznych zapewnia składnię do tworzenia systemów rozproszonych. Język C# ma ujednolicony system typów. Wszystkie typy języka C#, w tym typy pierwotne, takie jak int i double, dziedziczą po pojedynczym typie object głównym. Wszystkie typy współdzielą zestaw typowych operacji. Wartości dowolnego typu mogą być przechowywane, transportowane i obsługiwane w spójny sposób. Ponadto język C# obsługuje zarówno zdefiniowane przez użytkownika typy referencyjne, jaki typy wartości. Język C# umożliwia dynamiczną alokację obiektów i przechowywanie w wierszu lekkich struktur. Język C# obsługuje metody i typy ogólne, które zapewniają większe bezpieczeństwo i wydajność typów. Język C# udostępnia iteratory, które umożliwiają implementatorom klas kolekcji definiowanie niestandardowych zachowań dla kodu klienta.

Język C# kładzie nacisk na wersje, aby zapewnić, że programy i biblioteki mogą rozwijać się wraz z czasem w zgodny sposób. Aspekty projektu języka C#virtualoverride, na które miały bezpośredni wpływ zagadnienia dotyczące obsługi wersji, obejmują oddzielne i modyfikatory, reguły rozpoznawania przeciążenia metod oraz obsługę jawnych deklaracji członków interfejsu.

Architektura .NET

Programy w języku C# działają na platformie .NET— wirtualnym systemie wykonywania nazywanym środowiskiem uruchomieniowym języka wspólnego (CLR) i zestawem bibliotek klas. ClR to implementacja przez firmę Microsoft infrastruktury języka wspólnego (CLI), standardu międzynarodowych. Interfejs wiersza polecenia stanowi podstawę do tworzenia środowisk wykonywania i programowania, w których języki i biblioteki współpracują bezproblemowo.

Kod źródłowy napisany w języku C# jest kompilowany do języka pośredniego (IL), który jest zgodny ze specyfikacją interfejsu wiersza polecenia. Kod IL i zasoby, takie jak mapy bitowe i ciągi, są przechowywane w zestawie, zwykle z rozszerzeniem .dll. Zestaw zawiera manifest, który dostarcza informacje o typach, wersji i kulturze zestawu.

Podczas wykonywania programu w języku C# zestaw jest ładowany do clr. ClR wykonuje kompilację Just-In-Time (JIT) w celu przekonwertowania kodu IL na instrukcje natywne komputera. ClR udostępnia inne usługi związane z automatycznym odzyskiwaniem pamięci, obsługą wyjątków i zarządzaniem zasobami. Kod wykonywany przez clr jest czasami nazywany "kodem zarządzanym". "Kod niezamanagedowany" jest kompilowany do natywnego języka maszynowego, który jest przeznaczony dla określonej platformy.

Współdziałanie języków jest kluczową funkcją .NET. Kod IL generowany przez kompilator języka C# jest zgodny ze specyfikacją typu wspólnego (CTS, Common Type Specification). Kod IL wygenerowany w języku C# może wchodzić w interakcje z kodem wygenerowanym na podstawie wersji języka F#, Visual Basic, C++. Istnieje ponad 20 innych języków zgodnych ze standardem CTS. Pojedynczy zestaw może zawierać wiele modułów napisanych w różnych językach .NET. Typy mogą odwoływać się do siebie tak, jakby były napisane w tym samym języku.

Oprócz usług czasu uruchamiania program .NET zawiera również rozbudowane biblioteki. Te biblioteki obsługują wiele różnych obciążeń. Są one zorganizowane w przestrzenie nazw, które zapewniają szeroką gamę przydatnych funkcji. Biblioteki obejmują wszystko, od danych wejściowych i wyjściowych do manipulowania ciągami, przez analizowanie kodu XML, przez struktury aplikacji internetowych po kontrolki Windows Forms. Typowa aplikacja w języku C# w szerokim zastosowaniem korzysta z biblioteki klas .NET w celu obsługi typowych prac "instalacyjnych".

Aby uzyskać więcej informacji o platformie .NET, zobacz Omówienie .NET.

Hello world

Program "Hello, World" jest tradycyjnie używany do wprowadzenia języka programowania. Tutaj jest w języku C#:

using System;

class Hello
{
    static void Main()
    {
        Console.WriteLine("Hello, World");
    }
}

Program "Hello, World" rozpoczyna się od dyrektywy using , która odwołuje się do przestrzeni System nazw. Przestrzenie nazw zapewniają hierarchiczne sposoby organizowania bibliotek i programów w języku C#. Przestrzenie nazw System zawierają typy i inne przestrzenie nazw — na przykład przestrzeń nazw zawiera wiele typów, Console takich jak klasa przywołyowana w programie, oraz wiele innych przestrzeni nazw, takich jak IO i Collections. Dyrektywa using , która odwołuje się do danej przestrzeni nazw, umożliwia niekwalifikowane użycie typów, które są członkami tej przestrzeni nazw. Ze względu na using dyrektywę program może używać jako Console.WriteLine skrótu dla .System.Console.WriteLine

Klasa Hello zadeklarowana przez program "Hello, World" ma jeden członek, czyli metodę o nazwie Main. Metoda Main jest zadeklarowana za pomocą static modyfikatora . Metody wystąpienia mogą odwoływać się do określonego otaczającego wystąpienia obiektu przy thisużyciu słowa kluczowego , metody statyczne działają bez odwołania do określonego obiektu. Zgodnie z konwencją metoda statyczna Main o nazwie służy jako punkt wejścia programu w języku C#.

Dane wyjściowe programu są produkowane przez metodę WriteLine klasy w Console przestrzeni System nazw . Ta klasa jest dostarczana przez standardowe biblioteki klas, które domyślnie są automatycznie przywołyne przez kompilator.

Typy i zmienne

Typ definiuje strukturę i zachowanie dowolnych danych w języku C#. Deklaracja typu może obejmować jego składowe, typ podstawowy, implementowane interfejsy i operacje dozwolone dla tego typu. Zmienna to etykieta, która odwołuje się do wystąpienia określonego typu.

Istnieją dwa rodzaje typów w języku C#: typy wartości itypy referencyjne. Zmienne typów wartości bezpośrednio zawierają swoje dane. Zmienne typów odwołań przechowują odwołania do ich danych, a te drugie są nazywane obiektami. W przypadku typów referencyjnych dwie zmienne mogą odwoływać się do tego samego obiektu i operacje na jednej zmiennej mogą mieć wpływ na obiekt przywołyny przez drugą zmienną. W przypadku typów wartości zmienne mają własną kopię danych i nie jest możliwe, aby operacje na jednej z nich wpływały na drugą ( refout z wyjątkiem zmiennych parametrów i ).

Identyfikator jest nazwą zmiennej. Identyfikator to sekwencja znaków Unicode bez żadnych białych znaków. Identyfikator może być słowem zarezerwowanym w języku C#, jeśli jest poprzedzony prefiksem @. Używanie słowa zastrzeżonego jako identyfikatora może być przydatne podczas interakcji z innymi językami.

Typy wartości języka C# są dalej podzielone na typy proste, typy wyliczeń , typy struktur, typy wartości dopuszczające wartość null i typy wartości krotki. Typy referencyjne języka C# są dalej podzielone na typy klas, typy interfejsów, typy tablic i typy delegatów.

Poniższy konspekt zawiera omówienie systemu typów języka C#.

Programy w języku C# używają deklaracji typów do tworzenia nowych typów. Deklaracja typu określa nazwę i elementy członkowskie nowego typu. Sześć kategorii typów języka C# można definiować przez użytkownika: typy klas, typy struktur, typy interfejsów, typy wyliczeń, typy delegatów i typy wartości krotki. Można również deklarować record typy , record structlub record class. Typy rekordów mają składowe syntetyzowane przez kompilator. Rekordy są przeznaczone głównie do przechowywania wartości z minimalnym skojarzonym zachowaniem.

  • Typ class definiuje strukturę danych, która zawiera składowe danych (pola) i składowe funkcji (metody, właściwości i inne). Typy klas obsługują pojedyncze dziedziczenie i polimorfizm, mechanizmy, w których klasy pochodne mogą rozszerzać i specjalizować klasy bazowe.
  • Typ struct jest podobny do typu klasy w tym, że reprezentuje strukturę z składowych danych i składowych funkcji. Jednak w przeciwieństwie do klas struktury są typami wartości i zwykle nie wymagają alokacji sterty. Typy struktur nie obsługują dziedziczenia określonego przez użytkownika, a wszystkie typy struktur niejawnie dziedziczą po typie object.
  • Typ interface definiuje kontrakt jako nazwany zestaw publicznych elementów członkowskich. Element class lub struct , który implementuje interface element , musi zapewniać implementacje elementów członkowskich interfejsu. Element interface może dziedziczyć z wielu interfejsów podstawowych, a class element lub struct może implementować wiele interfejsów.
  • Typ delegate reprezentuje odwołania do metod z listą określonych parametrów i zwracany typ. Delegaty mogą traktować metody jako jednostki, które można przypisać do zmiennych i przekazać jako parametry. Delegaty są analogiczne do typów funkcji dostarczanych przez języki funkcjonalne. Są one również podobne do koncepcji wskaźników funkcji w niektórych innych językach. W przeciwieństwie do wskaźników funkcji delegaci są zorientowani obiektowo i bezpieczni pod typem.

Typy class, struct, interfacei obsługują delegate typy ogólne, dzięki którym mogą być sparametryzowane z innymi typami.

Język C# obsługuje tablice jednowymiarowe i wielowymiarowe dowolnego typu. W przeciwieństwie do typów wymienionych powyżej, typy tablic nie muszą być zadeklarowane przed ich rozpoczęciem. Zamiast tego typy tablic są konstruowane według nazwy typu z nawiasami kwadratowymi. Na przykład int[]intjest tablicą jednowymiarową typu , intint[,]int[][] jest dwuwymiarową tablicą , a jest jednowymiarową tablicą tablic jednowymiarowych lub tablicą "oflagowana" o intwartości .

Typy dopuszczane wartością null nie wymagają oddzielnej definicji. Dla każdego typu, który nie dopuszcza wartości Tnull, istnieje odpowiedni typ dopuszczania wartości null T?, który może przechowywać dodatkową wartość, null. Na przykład jest int? typem, który może przechowywać dowolną 32-bitową nullliczbę całkowitą lub wartość , string? i jest typem, który może przechowywać dowolną nullstring wartość lub .

System typów języka C# jest ujednolicony w taki sposób, że wartość dowolnego typu może być traktowana jako object. Każdy typ w języku C# bezpośrednio lub pośrednio objectobject pochodzi od typu klasy i jest ostateczną klasą bazową wszystkich typów. Wartości typów referencyjnych są traktowane jako obiekty poprzez wyświetlanie wartości jako typu object. Wartości typów wartości są traktowane jako obiekty przez wykonywanie operacji boxing i unboxing. W poniższym przykładzie wartość int jest konwertowana na object wartość i z powrotem do wartości int.

int i = 123;
object o = i;    // Boxing
int j = (int)o;  // Unboxing

Gdy wartość typu wartości jest przypisana do object odwołania, przydzielane jest "pole" do przechowywania wartości. To pole jest wystąpieniem typu odwołania, a wartość jest kopiowana do tego pola. I odwrotnie, gdy object odwołanie jest rzutowane na typ wartości, sprawdza się, object czy odwołanie jest polem poprawnego typu wartości. Jeśli sprawdzenie zakończy się powodzeniem, wartość w polu zostanie skopiowana do typu wartości.

Ujednolicony system typów języka C# oznacza, że typy wartości są traktowane jako object odwołania "na żądanie". Ze względu na ujednoznaknienie bibliotek objectobjectogólnego przeznaczenia, które używają typu , można używać ze wszystkimi typami, które pochodzą od typu , w tym zarówno typami referencyjnymi, jak i typami wartości.

W języku C# istnieje kilka rodzajów zmiennych, w tym pola, elementy tablicy, zmienne lokalne i parametry. Zmienne reprezentują lokalizacje magazynu. Każda zmienna ma typ, który określa, jakie wartości mogą być przechowywane w zmiennej, jak pokazano poniżej.

  • Typ wartości nienadajnej do wartości null
    • Wartość tego dokładnego typu
  • Typ wartości dopuszczania wartości null
    • Wartość null lub wartość tego dokładnego typu
  • object
    • Odwołanie null , odwołanie do obiektu dowolnego typu referencyjnego lub odwołanie do wartości boxed dowolnego typu wartości
  • Typ klasy
    • Odwołanie null , odwołanie do wystąpienia tego typu klasy lub odwołanie do wystąpienia klasy pochodzącej od tego typu klasy
  • Typ interfejsu
    • Odwołanie null , odwołanie do wystąpienia typu klasy, które implementuje ten typ interfejsu, lub odwołanie do wartości boxed typu wartości, która implementuje ten typ interfejsu
  • Typ tablicy
    • Odwołanie null , odwołanie do wystąpienia tego typu tablicy lub odwołanie do wystąpienia zgodnego typu tablicy
  • Typ delegata
    • Odwołanie null lub odwołanie do wystąpienia zgodnego typu delegata

Struktura programu

Kluczowe pojęcia organizacyjne w języku C# to programy, przestrzenie nazw, typy, elementy członkowskiei zestawy. Programy deklarują typy, które zawierają elementy członkowskie i mogą być zorganizowane w przestrzenie nazw. Klasy, struktury i interfejsy są przykładami typów. Pola, metody, właściwości i zdarzenia są przykładami elementów członkowskich. Podczas kompilowania programów w języku C# są one fizycznie pakowane w zestawy. Zestawy zwykle mają rozszerzenie .exe pliku lub .dll, w zależności od tego, .exe odpowiednio aplikacje lub biblioteki.

Jako mały przykład rozważmy zestaw zawierający następujący kod:

namespace Acme.Collections;

public class Stack<T>
{
    Entry _top;

    public void Push(T data)
    {
        _top = new Entry(_top, data);
    }

    public T Pop()
    {
        if (_top == null)
        {
            throw new InvalidOperationException();
        }
        T result = _top.Data;
        _top = _top.Next;

        return result;
    }

    class Entry
    {
        public Entry Next { get; set; }
        public T Data { get; set; }

        public Entry(Entry next, T data)
        {
            Next = next;
            Data = data;
        }
    }
}

W pełni kwalifikowana nazwa tej klasy to Acme.Collections.Stack. Klasa zawiera kilka składowych: pole o nazwie _top, dwie metody o Push nazwach i Poporaz zagnieżdżone klasy o nazwie Entry. Ponadto Entry klasa zawiera trzy składowe: właściwość o nazwie Next, właściwość o nazwie Datai konstruktor. Jest StackStack . Ma jeden parametr typu, T który jest zastępowany konkretnym typem, gdy jest używany.

Stos jest kolekcją "pierwszy w — ostatni na końcu". Nowe elementy są dodawane w górnej części stosu. Po usunięciu elementu jest on usuwany z górnej części stosu. Poprzedni przykład deklaruje typ Stack , który definiuje magazyn i zachowanie stosu. Możesz zadeklarować zmienną, która odwołuje się do wystąpienia typu Stack , aby użyć tej funkcji.

Zestawy zawierają kod wykonywalny w postaci instrukcji języka pośredniego (IL) i informacje symboliczne w postaci metadanych. Przed jego wykonaniem kompilator JIT (Just-In-Time) środowiska .NET Common Language Runtime konwertuje kod IL w zestawie na kod specyficzny dla procesora.

Ponieważ zestaw jest samoopisywania jednostki funkcji zawierającej zarówno kod, jak i metadane, #include nie ma potrzeby dyrektyw i plików nagłówków w języku C#. Typy publiczne i elementy członkowskie zawarte w określonym zestawie są udostępniane w programie języka C# poprzez odwołanie się do tego zestawu podczas kompilowania programu. Na przykład ten program używa klasy Acme.Collections.Stack z zestawu acme.dll :

class Example
{
    public static void Main()
    {
        var s = new Acme.Collections.Stack<int>();
        s.Push(1); // stack contains 1
        s.Push(10); // stack contains 1, 10
        s.Push(100); // stack contains 1, 10, 100
        Console.WriteLine(s.Pop()); // stack contains 1, 10
        Console.WriteLine(s.Pop()); // stack contains 1
        Console.WriteLine(s.Pop()); // stack is empty
    }
}

Aby skompilować ten program, należy odwołać się do zestawu zawierającego klasę stosu zdefiniowaną we wcześniejszym przykładzie.

Programy w języku C# mogą być przechowywane w kilku plikach źródłowych. Podczas kompilowania programu w języku C# wszystkie pliki źródłowe są przetwarzane razem, a pliki źródłowe mogą swobodnie odwoływać się do siebie nawzajem. Koncepcyjnie jest to tak, jakby wszystkie pliki źródłowe zostały zsuowane w jeden duży plik przed przetworzeniem. Deklaracje przekazywania nigdy nie są potrzebne w języku C#, ponieważ z kilkoma wyjątkami kolejność deklaracji jest nieistotna. Język C# nie ogranicza pliku źródłowego do deklarowania tylko jednego typu publicznego ani nie wymaga, aby nazwa pliku źródłowego była dopasowana do typu zadeklarowanej w pliku źródłowym.

Dalsze artykuły w tym przewodniku wyjaśniają te bloki organizacyjne.