Typy (Przewodnik programowania w języku C#)
Typy, zmienne i wartości
C# jest językiem jednoznacznym.Każda zmienna i stała ma przypisany typ, podobnie jak każde wyrażenie odnoszące się do wartości.Każdy podpis metody określa typ dla każdego parametru wejściowego i dla zwróconej wartości.Biblioteka klas .NET Framework definiuje zestaw wbudowanych typów liczbowych, jak również bardziej złożonych typów, które reprezentują szeroką gamę konstrukcji logicznych, takie jak system plików, połączenia sieciowe, kolekcje i tablice obiektów i daty.Typowy program w C# korzysta z typów z biblioteki klas, jak również typów zdefiniowanych przez użytkownika, które modelują koncepcje, które są specyficzne dla programu dziedziny problemu.
Informacje przechowywane w polu typ mogą być następujące:
Przestrzeń przechowywania wymagana przez typ zmiennej.
Wartości maksymalne i minimalne, które może reprezentować.
Członkowie (metody, pola, zdarzenia i tak dalej), które zawiera.
Typ podstawowy, z którego dziedziczy.
Miejsce, gdzie pamięć dla zmiennych będzie przydzielona podczas wykonywania.
Rodzaje operacji, które są dozwolone.
Kompilator używa informacji o typie, aby upewnić się, że wszystkie operacje, które są wykonywane w kodzie są bezpiecznego typu.Jeśli na przykład zadeklarujesz zmienną typu int, kompilator umożliwi dodatkowo użycie tej zmiennej w operacjach dodawania i odejmowania.Jeśli próbujesz wykonać te same operacje na zmiennej typu bool, kompilator generuje błąd, jak pokazano w następującym przykładzie:
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]
Programiści C i C++, zauważają, że w języku C#, bool nie jest konwertowany na int.
Kompilator osadza informacje o typie pliku wykonywalnego jako metadane.Środowisko uruchomieniowe języka wspólnego (CLR) używa tych metadanych w czasie wykonywania, by zapewnić bezpieczeństwo typów, gdy przydziela i przejmuje pamięć.
Określanie typów w deklaracjach zmiennych
Kiedy deklarujesz zmienną lub stałą w programie, musisz określić jej typ lub użyć słowa kluczowego var, aby pozwolić kompilatorowi wydedukować typ.W poniższym przykładzie pokazano kilka deklaracji zmiennych, korzystających z wbudowanych typów liczbowych i złożonych typów zdefiniowanych przez użytkownika:
// Declaration only:
float temperature;
string name;
MyClass myClass;
// Declaration with initializers (four examples):
char firstLetter = 'C';
var limit = 3;
int[] source = { 0, 1, 2, 3, 4, 5 };
var query = from item in source
where item <= limit
select item;
Typy parametrów metody i wartości zwracane są określone w oznaczeniu metody.Następująca sygnatura przedstawia metodę, która wymaga int jako argumentu wejściowego i zwraca ciąg:
public string GetName(int ID)
{
if (ID < names.Length)
return names[ID];
else
return String.Empty;
}
private string[] names = { "Spencer", "Sally", "Doug" };
Po zadeklarowaniu zmiennej nie może być ona ponownie zadeklarowana i nie można przypisać jej wartości, która nie jest zgodna z deklarowanym typem.Na przykład nie można zadeklarować int, a następnie przypisać mu wartości logicznej true.Jednakże wartości można przekonwertować do innych typów, na przykład gdy są one przypisane do nowych zmiennych lub przekazywane jako argumenty tej metody.Konwersja typu która nie powoduje utraty danych jest wykonywana automatycznie przez kompilator.Wymaga konwersji, która może spowodować utratę danych Obsada w kodzie źródłowym.
Aby uzyskać więcej informacji, zobacz Rzutowanie i konwersje typów (Przewodnik programowania w języku C#).
Typy wbudowane
C# zawiera standardowy zestaw wbudowanych typów liczbowych do reprezentowania liczb całkowitych, pływające wartości punktów, wyrażenia logiczne, znaki tekstowe, wartości dziesiętne i innych typy danych.Istnieją również typy wbudowane string oraz object.Są dostępne do użytku w każdym programie C#.Aby uzyskać więcej informacji na temat wbudowanych typów, zobacz Tabele odwołań dla typów (odwołanie w C#).
Niestandardowe typy
Aby utworzyć własne niestandardowe typy należy użyć konstrukcji struktura, klasa, interfejs oraz enum.Sama biblioteka klas .NET Framework jest kolekcją typów niestandardowych dostarczonych przez firmę Microsoft, których można używać we własnych aplikacjach.Domyślnie najczęściej używane typy w bibliotece klas są dostępne w dowolnym programie C#.Inne stają się dostępne tylko wtedy, gdy użytkownik jawnie doda odwołanie do projektu do zestawu, w którym są zdefiniowane.Po tym jak kompilator wykona odwołanie do zestawu, można deklarować zmienne (i stałe) typy zadeklarowane w tym zgromadzeniu w kodzie źródłowym.Aby uzyskać więcej informacji, zobacz Biblioteka klasy .NET Framework.
Wspólny system typów.
Ważne jest, aby zrozumieć dwa podstawowe punkty o systemie typu w .NET Framework:
Obsługuje zasady dziedziczenia.Typy mogą pochodzić od innych typów nazywanych typami bazowymi.Typ pochodny dziedziczy (z pewnymi ograniczeniami) metody, właściwości i innych członków tego typu podstawowego.Typ podstawowy z kolei może pochodzić od innego typu, w którym to przypadku typ pochodny dziedziczy członków obu typów podstawowych w swojej hierarchii dziedziczenia.Wszystkie typy, w tym wbudowane typy liczbowe, takie jak Int32 (słowo kluczowe języka C#: int), czerpią ostatecznie z jednego typu podstawowego, który jest Object (słowo kluczowe języka C#: obiektu).Ta ujednolicona hierarchia typu jest nazwana System typu wspólnego (CTS).Aby uzyskać więcej informacji dotyczących dziedziczenia w C#, zobacz Dziedziczenie (Przewodnik programowania w języku C#).
Każdy typ w CTS jest zdefiniowany jako wartości typu lub Typ odwołania.Obejmuje to wszystkie niestandardowe typy w bibliotece klas .NET Framework oraz również typy własne zdefiniowane przez użytkownika.Typy, które definiujesz z użyciem słowa kluczowego struct to typy wartości; wszystkie wbudowane typy liczbowe to structs.Typy, które definiujesz z użyciem słowa kluczowego klasa to typy odwołań.Typy odwołań i typy wartości mają różne zasady czasu kompilacji i różny sposób zachowania w czasie uruchomienia.
Na poniższej ilustracji przedstawiono związek między typami wartości a typami odwołań w CTS.
Typy wartości i typy odwołań w CTS
[!UWAGA]
Można zobaczyć, że najczęściej używane typy są zorganizowane w przestrzeni nazw System.Jednakże przestrzeń nazw, w której zawarty jest typ, nie ma związku z tym, czy jest to typ wartości, czy typ odwołania.
Typy wartości
Typy wartości wywodzą się z ValueType, które wywodzi się z Object.Typy, które pochodzą od ValueType maja specjalne zachowanie w CLR.Zmienne typu wartości bezpośrednio zawierają swoje wartości, co oznacza że pamięć jest alokowana wewnątrz niezależnie od kontekstu, w którym zadeklarowana jest zmienna.Nie ma oddzielnej alokacji stosu lub wyrzucania elementów bezużytecznych dla zmiennych typu wartości.
Istnieją dwie kategorie typów wartości: ustrukturyzowana oraz enumeracyjna.
Wbudowane typy liczbowe są strukturami i mają właściwości i metody, do których można uzyskać dostęp:
// Static method on type Byte.
byte b = Byte.MaxValue;
Ale zadeklarować i przypisać wartości do nich tak, jakby były prostymi typami-aggregacji:
byte num = 0xA;
int i = 5;
char c = 'Z';
Typy wartości są zaplombowane, co oznacza, na przykład, że nie możesz wywodzić typu z Int32 i nie możesz definiować dziedziczenia struktury od żadnej klasy definiowanej przez użytkownika ani struktury, ponieważ struktura może dziedziczyć tylko od ValueType.Jednakże struktura może zaimplementować jeden lub więcej interfejsów.Możesz rzucić typ strukturalny na typ interfejsu; powoduje to operację opakowywania, aby opakować typ strukturalny w obiekt typu odwołania na zarządzanym stosie.Operacje na polach występują, gdy wartość typu należy przekazać do metody, która przyjmuje Object jako parametr wejściowy.Aby uzyskać więcej informacji, zobacz Konwersja boxing i konwersja unboxing (Przewodnik programowania w języku C#).
Aby utworzyć własne typy niestandardowych wartości należy użyć słowa kluczowego struktura.Typowo, struct jest używany jako kontener dla mniejszego zestawu powiązanych zmiennych, jak pokazani w poniższym przykładzie:
public struct CoOrds
{
public int x, y;
public CoOrds(int p1, int p2)
{
x = p1;
y = p2;
}
}
Aby uzyskać więcej informacji na temat struktur, zobacz Struktury (Przewodnik programowania w języku C#).Aby uzyskać więcej informacji dotyczących typów wartości w .NET Framework, zobacz System typu wspólnego.
Inna kategoria typu wartości to wyliczenie.Wyliczenie definiuje zestaw o nazwanych stałych liczbach całkowitych.Na przykład wyliczenie FileMode w bibliotece klasy .NET Framework zawiera zestaw nazwanych stałych liczb całkowitych, które określają, jak można otworzyć plik.Jest on zdefiniowany jak pokazano w poniższym przykładzie:
public enum FileMode
{
CreateNew = 1,
Create = 2,
Open = 3,
OpenOrCreate = 4,
Truncate = 5,
Append = 6,
}
Stała System.IO.FileMode.Create ma wartość 2.Jednak nazwa jest bardziej istotna dla ludzi czytających kod źródłowy i z tego powodu lepiej jest używać wyliczenia zamiast stałej liczby literału.Aby uzyskać więcej informacji, zobacz FileMode.
Wszystkie typy wyliczeniowe dziedziczą z elementu Enum, który dziedziczy z elementu ValueType.Wszystkie reguły, które dotyczą struktur stosuje się także do wyliczenia.Aby uzyskać więcej informacji na temat typów wyliczeń, zobacz Typy wyliczeniowe (Przewodnik programowania w języku C#).
Typy odwołań
Typ, który jest zdefiniowany jako klasa, delegat, tablica, lub interfejs jest Typem odwołania.W czasie wykonywania, jeśli zadeklarujemy zmienną typu odwołania, zmienna zawiera wartość null aż jawnie tworzone jest wystąpienie obiektu za pomocą Nowy operatora, lub gdzie indziej utworzoną za pomocą obiektunew, as shown in the following example:
MyClass mc = new MyClass();
MyClass mc2 = mc;
Interfejs musi być zainicjowany razem z obiektem klasy, który implementuje go.Jeśli MyClass implementuje IMyInterface, można utworzyć wystąpienie IMyInterface, jak pokazano w następującym przykładzie:
IMyInterface iface = new MyClass();
Po utworzeniu obiektu, pamięć jest alokowane na zarządzanym stosie, a zmienna zawiera tylko odwołanie do lokalizacji obiektu.Typy na zarządzanym stosie wymagają narzutu zarówno kiedy są alokowane oraz kiedy są odbierane przez funkcjonalność zarządzania pamięcią automatyczną CLR, co jest znane jako wyrzucanie elementów bezużytecznych.Jednak wyrzucanie elementów bezużytecznych jest również bardzo dobrze zoptymalizowane i w większości scenariuszy nie powoduje problemów z wydajnością.Aby uzyskać więcej informacji dotyczących wyrzucania elementów bezużytecznych, zobacz Automatyczne zarządzanie pamięcią.
Wszystkie tablice są typami odwołań, nawet jeśli ich elementy są typami wartości.Tablice niejawnie pochodzą od Array klasy, ale deklarujes zje i używasz ich z uproszczoną skłądnią, która jest dostarczana przez C#, jak pokazano w następującym przykładzie:
// Declare and initialize an array of integers.
int[] nums = { 1, 2, 3, 4, 5 };
// Access an instance property of System.Array.
int len = nums.Length;
Typy odwołań w pełni obsługują dziedziczenie.Kiedy tworzysz klasę, możesz dziedziczyć od innego interfejsu lub klasy, która nie jest zdefiniowana jako zaplombowana, a inne klasy mogą dziedziczyć od Twojej klasy i zastępować Twoje wirtualne metody.Aby uzyskać więcej informacji dotyczących tworzenia własnych klas, zobacz Klasy i struktury (Przewodnik programowania w języku C#).Aby uzyskać więcej informacji dotyczących dziedziczenia i metod wirtualnych, zobacz Dziedziczenie (Przewodnik programowania w języku C#).
Typy wartości literałów
W języku programowania C# wartości literału otrzymują typ z kompilatora.Możesz określić jak literał liczbowy powinien być wpisywany przez dołączenia litery na końcu numeru.Na przykład aby określić, że wartość 4,56 ma być traktowana jako zmiennoprzecinkowa, należy dołączyć "f" lub "F" po liczbie: 4.56f.Jeśli żadna litera nie zostanie dołączona, kompilator wywnioskuje typ dla literału.Aby uzyskać więcej informacji dotyczących typów, które można określić za pomocą literowych sufiksów, zobacz strony pomocy dla poszczególnych typów w Typy wartości (odwołanie w C#).
Ponieważ wpisywane są literały, a wszystkie typy ostatecznie pochodzą od Object, można pisać i kompilować następujący kod:
string s = "The answer is " + 5.ToString();
// Outputs: "The answer is 5"
Console.WriteLine(s);
Type type = 12345.GetType();
// Outputs: "System.Int32"
Console.WriteLine(type);
Typ ogólny
Typ może być zadeklarowany w jednym lub więcej parametrów typu, które służą jako symbolem zastępczego dla rzeczywistego typu (konkretnego typu) które kod klienta zapewni podczas tworzenia wystąpienia tego typu.Typy takie są określane mianem typów ogólnych.Na przykład typ .NET Framework List ma jeden parametr typu, który zgodnie z konwencją ma nazwę T.Podczas tworzenia wystąpienia typu, określasz typ obiektów, które zawierać będzie lista, przykładowo ciąg:
List<string> strings = new List<string>();
Zastosowanie parametrów typu umożliwia ponowne użycie tej samej klasy do utrzymania jakiegokolwiek typu elementu, bez konieczności konwersji każdego elementu na obiekt.Klasy ogólne kolekcji są nazywane kolekcjami jednoznacznymi, ponieważ kompilator zna określony typ elementów kolekcji i może zgłosić błąd w czasie kompilacji, jeśli na przykład spróbujesz dodać liczbę całkowitą do obiektu strings w poprzednim przykładzie.Aby uzyskać więcej informacji, zobacz Typy ogólne (Przewodnik programowania w języku C#).
Typy niejawne, anonimowe i dopuszczające wartości null
Jak wspomniano wcześniej, można niejawnie wpisać zmienną lokalną (ale nie elementy klas) za pomocą var. słowa kluczowego.Zmienna wciąż otrzymuje typ w czasie kompilacji, ale typ jest dostarczany przez kompilator.Aby uzyskać więcej informacji, zobacz Niejawnie wpisane zmienne lokalne (Przewodnik programowania w języku C#).
W niektórych przypadkach nie jest wygodne, aby tworzyć nazwany typ dla prostych zestawów powiązanych wartości, które nie będą przechowywane lub przekazywane poza granice metody.Możesz utworzyć w tym celu typy anonimowe.Aby uzyskać więcej informacji, zobacz Typy anonimowe (Przewodnik programowania w języku C#).
Typy wartości zwykłych nie mogą przyjmować wartości null.Możesz jednak utworzyć typy dopuszczające wartości null przez umieszczenie ? po typie.Na przykład int? jest typem int, który może mieć również wartość null.W CTS, typy null są wystąpieniami typu struktury ogólnej Nullable.Typy dopuszczające wartości null są szczególnie przydatne podczas przekazywania danych do i z baz danych, w których wartości liczbowe mogą przyjąć wartość null.Aby uzyskać więcej informacji, zobacz Typy dopuszczające wartości zerowe (Przewodnik programowania w języku C#).
Sekcje pokrewne
Aby uzyskać więcej informacji, zobacz następujące tematy:
Rzutowanie i konwersje typów (Przewodnik programowania w języku C#)
Konwersja boxing i konwersja unboxing (Przewodnik programowania w języku C#)
Używanie typu dynamicznego (Przewodnik programowania w języku C#)
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#.
Zobacz też
Informacje
Tabela typów całkowitych (odwołanie w C#)
Koncepcje
Przewodnik programowania w języku C#