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#virtual
override
, 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 this
uż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ą ( ref
out
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#.
- Typy wartości
- Typy proste
- Całkowita ze podpisem: ,
short
,int
,long
- Nieoznakowana całkowita: ,
ushort
,uint
,ulong
- Znaki Unicode: , który reprezentuje jednostkę kodu UTF-16
- Binarny zmiennoprzecinek IEEE: ,
double
- Liczba zmiennoprzecinkowa dziesiętna o wysokiej dokładności:
- Wartość logiczna:
bool
, która reprezentuje wartości logiczne — wartości, które są lubtrue
false
- Całkowita ze podpisem: ,
- Typy wyli
- Zdefiniowane przez użytkownika typy formularza
enum E {...}
. Typenum
jest odrębnym typem z nazwanych stałych. Każdyenum
typ ma typ podstawowy, który musi być jednym z ośmiu typów całkowitocowych. Zestaw wartości typu jestenum
taki sam jak zestaw wartości typu bazowego.
- Zdefiniowane przez użytkownika typy formularza
- Typy struktur
- Typy zdefiniowane przez użytkownika formularza
struct S {...}
- Typy zdefiniowane przez użytkownika formularza
- Typy wartości dopuszczające wartość null
- Rozszerzenia wszystkich innych typów wartości z wartością
null
- Rozszerzenia wszystkich innych typów wartości z wartością
- Typy wartości krotki
- Typy zdefiniowane przez użytkownika formularza
(T1, T2, ...)
- Typy zdefiniowane przez użytkownika formularza
- Typy proste
- Typy odwołań
- Typy klas
- Ultimate, klasa bazowa wszystkich innych typów:
object
- Ciągi Unicode: , które reprezentują sekwencję jednostek kodu UTF-16
- Typy zdefiniowane przez użytkownika formularza
class C {...}
- Ultimate, klasa bazowa wszystkich innych typów:
- Typy interfejsów
- Typy zdefiniowane przez użytkownika formularza
interface I {...}
- Typy zdefiniowane przez użytkownika formularza
- Typy tablic
- Jednowymiarowe, wielowymiarowe i oflagowane. Na przykład:
int[]
,int[,]
iint[][]
- Jednowymiarowe, wielowymiarowe i oflagowane. Na przykład:
- Typy delegatów
- Typy zdefiniowane przez użytkownika formularza
delegate int D(...)
- Typy zdefiniowane przez użytkownika formularza
- Typy klas
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 struct
lub 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 typieobject
. - Typ
interface
definiuje kontrakt jako nazwany zestaw publicznych elementów członkowskich. Elementclass
lubstruct
, który implementujeinterface
element , musi zapewniać implementacje elementów członkowskich interfejsu. Elementinterface
może dziedziczyć z wielu interfejsów podstawowych, aclass
element lubstruct
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
, interface
i 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[]
int
jest tablicą jednowymiarową typu , int
int[,]
int[][]
jest dwuwymiarową tablicą , a jest jednowymiarową tablicą tablic jednowymiarowych lub tablicą "oflagowana" o int
wartości .
Typy dopuszczane wartością null nie wymagają oddzielnej definicji. Dla każdego typu, który nie dopuszcza wartości T
null, 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ą null
liczbę całkowitą lub wartość , string?
i jest typem, który może przechowywać dowolną null
string
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 object
object
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 object
object
ogó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
- Wartość
- object
- Odwołanie
null
, odwołanie do obiektu dowolnego typu referencyjnego lub odwołanie do wartości boxed dowolnego typu wartości
- Odwołanie
- 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
- Odwołanie
- 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
- Odwołanie
- Typ tablicy
- Odwołanie
null
, odwołanie do wystąpienia tego typu tablicy lub odwołanie do wystąpienia zgodnego typu tablicy
- Odwołanie
- Typ delegata
- Odwołanie
null
lub odwołanie do wystąpienia zgodnego typu delegata
- Odwołanie
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 Pop
oraz 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 Data
i konstruktor. Jest Stack
Stack
. 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.