Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Wskazówka
Dopiero zaczynasz programować oprogramowanie? Najpierw zacznij od samouczków Wprowadzenie . Przeprowadzą Cię przez pisanie programów i wprowadzają typy w miarę postępów.
Czy masz doświadczenie w pracy w innym języku? Jeśli już rozumiesz systemy typów, przejrzyj różnicę między wartością a referencją oraz przewodnik wybierania typu, następnie przejdź do artykułów o określonych typach.
C# to silnie typizowany język. Każda zmienna, stała i wyrażenie mają typ. Kompilator wymusza bezpieczeństwo typu , sprawdzając, czy każda operacja w kodzie jest prawidłowa dla zaangażowanych typów. Możesz na przykład dodać dwie int wartości, ale nie można dodać elementu int i :bool
int a = 5;
int b = a + 2; // OK
bool test = true;
// Error. Operator '+' cannot be applied to operands of type 'int' and 'bool'.
// int c = a + test;
Uwaga / Notatka
W przeciwieństwie do języka C i C++, w języku C#, bool nie jest konwertowany na int.
Bezpieczeństwo typów wykrywa błędy w czasie kompilacji, zanim Twój kod zacznie działać. Kompilator osadza również informacje o typie w pliku wykonywalnym jako metadane, których środowisko uruchomieniowe języka wspólnego (CLR) używa do dodatkowych kontroli bezpieczeństwa w czasie wykonywania.
Deklarowanie zmiennych z typami
Podczas deklarowania zmiennej należy jawnie określić jego typ lub użyć var go, aby kompilator wywnioskować typ z przypisanej wartości:
// Explicit type:
int count = 10;
double temperature = 36.6;
// Compiler-inferred type:
var name = "C#";
var items = new List<string> { "one", "two", "three" };
Parametry metody i wartości zwracane mają również typy. Poniższa metoda przyjmuje element string i int, i zwraca element string:
static string GetGreeting(string name, int visitCount)
{
return visitCount switch
{
1 => $"Welcome, {name}!",
_ => $"Welcome back, {name}! Visit #{visitCount}."
};
}
Po zadeklarowaniu zmiennej nie można zmienić jej typu ani przypisać wartości niezgodnej z zadeklarowanym typem. Wartości można konwertować na inne typy. Kompilator wykonuje niejawne konwersje , które nie tracą danych automatycznie. Jawne konwersje (rzuty) wymagają wskazania konwersji w kodzie. Aby uzyskać więcej informacji, zobacz Rzutowanie i konwersje typów.
Typy wbudowane i typy niestandardowe
Język C# udostępnia wbudowane typy typowych danych: liczby całkowite, liczby zmiennoprzecinkowe, bool, chari string. Każdy program w języku C# może używać tych wbudowanych typów bez dodatkowych odwołań.
Poza wbudowanymi typami można tworzyć własne typy przy użyciu kilku konstrukcji:
- Klasy — typy odwołań do modelowania zachowań i tworzenia złożonych obiektów. Obsługa dziedziczenia i polimorfizmu.
- Struktury — typy wartości dla małych, lekkich danych. Każda zmienna przechowuje własną kopię.
-
Rekordy — klasy lub struktury z równością wygenerowaną przez kompilator,
ToStringi niedestrukcyjną mutacją za pomocąwithwyrażeń. - Interfejsy — kontrakty definiujące składowe, które dowolna klasa lub struktura może implementować.
- Wyliczenia — nazwane zestawy stałych całkowitych, takie jak dni tygodnia lub tryby dostępu do plików.
- Krotki — uproszczone typy strukturalne grupujące powiązane wartości bez definiowania nazwanego typu.
-
Generyki — konstrukcje sparametryzowane typem, takie jak
List<T>iDictionary<TKey, TValue>, które zapewniają bezpieczeństwo typu przy ponownym użyciu tej samej logiki dla różnych typów.
Typy wartości i typy referencyjne
Każdy typ w języku C# jest typem wartości lub typem odwołania. To rozróżnienie określa, jak zmienne przechowują dane i jak działa przypisanie.
Typy wartości przechowują swoje dane bezpośrednio. Po przypisaniu typu wartości do nowej zmiennej środowisko uruchomieniowe kopiuje dane. Zmiany w jednej zmiennej nie mają wpływu na drugą. Struktury, wyliczenia i wbudowane typy liczbowe to wszystkie typy wartości.
Typy odwołań przechowują odwołanie do obiektu na zarządzanym stosie. Po przypisaniu typu odwołania do nowej zmiennej oba zmienne wskazują ten sam obiekt. Zmiany w jednej zmiennej są widoczne przez drugą. Klasy, tablice, delegaty i ciągi są typami referencyjnymi.
W poniższym przykładzie przedstawiono różnicę. Pierwszy blok przedstawia definicję struktury rekordu Coords , która jest typem wartości. Drugi blok przedstawia różne zachowanie typów wartości i typów referencyjnych.
public readonly record struct Coords(int X, int Y);
// Value type: each variable holds its own copy
var point1 = new Coords(3, 4);
var point2 = point1;
Console.WriteLine($"point1: ({point1.X}, {point1.Y})");
Console.WriteLine($"point2: ({point2.X}, {point2.Y})");
// point1 and point2 are independent copies
// Reference type: both variables refer to the same object
var list1 = new List<int> { 1, 2, 3 };
var list2 = list1;
list2.Add(4);
Console.WriteLine($"list1 count: {list1.Count}"); // 4 — same object
Wszystkie typy ostatecznie pochodzą z klasy System.Object. Typy wartości pochodzą z System.ValueType, i te z kolei pochodzą z object. Ta ujednolicona hierarchia nosi nazwę Common Type System (CTS). Aby uzyskać więcej informacji na temat dziedziczenia, zobacz Dziedziczenie.
Wybierz rodzaj typu
Podczas definiowania nowego typu, wybór rodzaju kształtuje sposób działania twojego kodu. Skorzystaj z poniższych wskazówek, aby podjąć początkową decyzję:
- Krotka — tymczasowe grupowanie wartości, które nie wymaga nadawania nazwy typowi ani zachowania.
-
structlubrecord struct— małe dane (około 64 bajty lub mniej), semantyka wartości lub niezmienność. Struktury rekordów dodają równość opartą na wartościach iwithwyrażenia. -
record class— przede wszystkim dane o równości opartej na wartościach,ToStringi mutacji niestrukcyjnej. Obsługuje dziedziczenie. -
class— złożone zachowanie, polimorfizm lub stan modyfikowalny. Większość typów niestandardowych to klasy. -
interface— umowa, którą niepowiązane typy mogą implementować. Definiuje możliwości, a nie tożsamość. -
enum— stały zestaw nazwanych stałych, takich jak kody stanu lub opcje.
Więcej niż jedna opcja jest często rozsądna.
Typ czasu kompilacji i typ czasu wykonywania
Zmienna może mieć różne typy w czasie kompilacji i czasie wykonywania. Typ czasu kompilacji to zadeklarowany lub wywnioskowany typ w kodzie źródłowym. Typ czasu wykonywania to rzeczywisty typ wystąpienia, do których odwołuje się zmienna. Typ czasu wykonywania musi być taki sam jak typ czasu kompilacji lub typ, który pochodzi z niego lub implementuje go. Przypisanie jest prawidłowe tylko wtedy, gdy istnieje niejawna konwersja z typu czasu wykonywania na typ czasu kompilacji, taka jak konwersja identyczności, odwołania, boksowanie lub konwersja liczbowa.
// Compile-time and run-time types match:
string message = "Hello, world!";
// Compile-time type differs from run-time type:
object boxed = "This is a string at run time";
IEnumerable<char> characters = "abcdefghijklmnopqrstuvwxyz";
W poprzednim przykładzie boxed ma typ czasu kompilacji object, ale typ string czasu wykonywania. Przypisanie działa, ponieważ string pochodzi z elementu object. Podobnie characters ma typ czasu kompilacji IEnumerable<char>, a przypisanie działa, ponieważ string implementuje ten interfejs. Typ czasu kompilacji kontroluje rozstrzyganie przeciążeń i konwersje. Typ czasu wykonywania steruje wysyłaniem metody wirtualnej, is wyrażeniami i switch wyrażeniami.
Zobacz także
- typy wartości
- typy odwołań
- Wspólny system typów
Specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz Specyfikacja języka C#. Specyfikacja języka jest ostatecznym źródłem informacji o składni i użyciu języka C#.