Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Jazyk C# je jazyk silného typu. Každá proměnná a konstanta má typ, stejně jako každý výraz, který se vyhodnotí jako hodnota. Každá deklarace metody určuje název, typ a druh (hodnota, odkaz nebo výstup) pro každý vstupní parametr a návratovou hodnotu. Knihovna tříd .NET definuje předdefinované číselné typy a komplexní typy, které představují širokou škálu konstruktorů. Patří sem systém souborů, síťová připojení, kolekce a pole objektů a kalendářní data. Typický program jazyka C# používá typy z knihovny tříd a uživatelem definovaných typů, které modelují koncepty specifické pro doménu problému programu.
Informace uložené v typu můžou obsahovat následující položky:
- Prostor úložiště, který vyžaduje proměnná daného typu.
- Maximální a minimální hodnoty, které může představovat.
- Členové (metody, pole, události atd.), které obsahuje.
- Základní typ, ze něhož dědí.
- Rozhraní, která implementuje.
- Povolené operace.
Kompilátor používá informace o typu, aby se zajistilo, že všechny operace prováděné v kódu jsou typu bezpečné. Pokud například deklarujete proměnnou typu int
, kompilátor umožňuje použít proměnnou při sčítání a odčítání operací. Pokud se pokusíte provést stejné operace s proměnnou typu bool
, kompilátor vygeneruje chybu, jak je znázorněno v následujícím příkladu:
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;
Poznámka:
Vývojáři C a C++, všimněte si, že v jazyce C# bool
není převoditelný na int
.
Kompilátor vloží informace o typu do spustitelného souboru jako metadata. Modul CLR (Common Language Runtime) používá tato metadata za běhu k dalšímu zajištění bezpečnosti typů při přidělení a uvolnění paměti.
Určení typů v deklarací proměnných
Když deklarujete proměnnou nebo konstantu v programu, musíte buď zadat jeho typ, nebo použít var
klíčové slovo, aby kompilátor odvodil typ. Následující příklad ukazuje některé deklarace proměnných, které používají předdefinované číselné typy i složité uživatelem definované typy:
// 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ů metody a návratové hodnoty jsou zadány v deklaraci metody. Následující podpis ukazuje metodu, která vyžaduje int
jako vstupní argument a vrací řetězec:
public string GetName(int ID)
{
if (ID < names.Length)
return names[ID];
else
return String.Empty;
}
private string[] names = ["Spencer", "Sally", "Doug"];
Jakmile deklarujete proměnnou, nemůžete ji předefinovat novým typem a nemůžete přiřadit hodnotu, která není kompatibilní s deklarovaným typem. Nemůžete například deklarovat int
a pak ji přiřadit logickou hodnotu true
. Hodnoty je však možné převést na jiné typy, například když jsou přiřazeny k novým proměnným nebo předány jako argumenty metody.
Převod typu, který nezpůsobuje ztrátu dat, provádí kompilátor automaticky. Převod, který může způsobit ztrátu dat, vyžaduje přetypování ve zdrojovém kódu.
Další informace naleznete v tématu Přetypování a převody typů.
Vestavěné typy
Jazyk C# poskytuje standardní sadu předdefinovaných typů. Představují celá čísla, hodnoty s plovoucí desetinnou čárkou, logické výrazy, textové znaky, desetinné hodnoty a další typy dat. K dispozici jsou také předdefinované string
a object
typy. Tyto typy jsou k dispozici pro použití v libovolném programu jazyka C#. Úplný seznam předdefinovaných typů najdete v tématu Předdefinované typy.
Vlastní typy
Pomocí konstruktorů struct
, class
, interface
, enum
a record
vytvoříte vlastní typy. Samotná knihovna tříd .NET je kolekce vlastních typů, které můžete použít ve vlastních aplikacích. Ve výchozím nastavení jsou nejčastěji používané typy v knihovně tříd dostupné v libovolném programu jazyka C#. Ostatní budou k dispozici pouze v případech, kdy explicitně přidáte odkaz na projekt do sestavení, které je definuje. Jakmile kompilátor odkazuje na sestavení, můžete deklarovat proměnné (a konstanty) typů deklarovaných v daném sestavení ve zdrojovém kódu. Další informace naleznete v tématu Knihovna tříd .NET.
Jedním z prvních rozhodnutí, která provedete při definování typu, je rozhodnutí, který konstruktor se má pro váš typ použít. Následující seznam vám pomůže provést toto počáteční rozhodnutí. Možnosti se překrývají. Ve většině scénářů je více než jedna možnost rozumnou volbou.
- Pokud je velikost úložiště dat malá, maximálně 64 bajtů, zvolte
struct
neborecord struct
. - Pokud je typ neměnný nebo chcete nedestruktivní mutaci, zvolte
struct
neborecord struct
. - Pokud váš typ by měl mít sémantiku hodnot pro rovnost, zvolte
record class
neborecord struct
. - Pokud se typ primárně používá k ukládání dat, nikoli chování, zvolte
record class
neborecord struct
. - Pokud je typ součástí hierarchie dědičnosti, zvolte položku
record class
neboclass
. - Pokud typ používá polymorfismus, zvolte .
class
- Pokud je primárním účelem chování, zvolte
class
.
Systém společných typů
Je důležité porozumět dvěma základním bodům systému typů v .NET:
- Podporuje princip dědičnosti. Typy mohou být odvozeny od jiných typů, označovaných jako základní typy. Odvozený typ dědí (s určitými omezeními) metody, vlastnosti a další členy základního typu. Základní typ lze zase odvodit z jiného typu, v takovém případě odvozený typ dědí členy obou základních typů v hierarchii dědičnosti. Všechny typy, včetně předdefinovaných číselných typů, například System.Int32 (klíčové slovo jazyka C#:
int
), se odvozují nakonec z jednoho základního typu, což je System.Object (klíčové slovo jazyka C#:object
). Tato sjednocená hierarchie typů se nazývá Common Type System (CTS). Další informace o dědičnosti v jazyce C# najdete v tématu Dědičnost. - Každý typ v CTS je definován jako typ hodnoty nebo odkazový typ. Tyto typy zahrnují všechny vlastní typy v knihovně tříd .NET a také vlastní typy definované uživatelem. Typy, které definujete pomocí klíčového
struct
slova, jsou typy hodnot; všechny předdefinované číselné typy jsoustructs
. Typy, které definujete pomocí klíčovéhoclass
slova,record
jsou odkazové typy. Odkazové typy a typy hodnot mají různá pravidla pro kompilaci a různé chování za běhu.
Následující obrázek znázorňuje vztah mezi typy hodnot a odkazovými typy v CTS.
Poznámka:
Vidíte, že nejčastěji používané typy jsou všechny uspořádané do System oboru názvů. Obor názvů, ve kterém je typ obsažen, však nemá žádný vztah k tomu, zda se jedná o typ hodnoty nebo typ odkazu.
Třídy a struktury jsou dvěma ze základních konstruktorů systému běžných typů v .NET. Každá z nich je v podstatě datová struktura, která zapouzdřuje sadu dat a chování, které patří dohromady jako logická jednotka. Data a chování jsou členy třídy, struktury nebo záznamu. Členové zahrnují své metody, vlastnosti, události a tak dále, jak je uvedeno dále v tomto článku.
Deklarace třídy, struktury nebo záznamu je jako podrobný plán, který se používá k vytváření instancí nebo objektů za běhu. Pokud definujete třídu, strukturu nebo záznam s názvem Person
, Person
je název typu. Pokud deklarujete a inicializujete proměnnou p
typu Person
, p
se říká, že se jedná o objekt nebo instanci Person
. Je možné vytvořit více instancí stejného typu Person
a každá instance může mít ve svých vlastnostech a polích různé hodnoty.
Třída je referenční typ. Při vytvoření objektu typu obsahuje proměnná, ke které je objekt přiřazen, pouze odkaz na tuto paměť. Pokud je odkaz na objekt přiřazen k nové proměnné, nová proměnná odkazuje na původní objekt. Změny provedené prostřednictvím jedné proměnné se projeví v druhé proměnné, protože obě odkazují na stejná data.
Struktura je typ hodnoty. Při vytvoření struktury obsahuje proměnná, ke které je struktura přiřazena, vlastní data struktury. Když je struktura přiřazena k nové proměnné, zkopíruje se. Nová proměnná a původní proměnná proto obsahují dvě samostatné kopie stejných dat. Změny provedené v jedné kopii nemají vliv na druhou kopii.
Typy záznamů můžou být odkazové typy (record class
) nebo typy hodnot (record struct
). Typy záznamů obsahují metody, které podporují rovnost hodnot.
Obecně se třídy používají k modelování složitějšího chování. Třídy obvykle ukládají data, která mají být změněna po vytvoření objektu třídy. Struktury jsou nejvhodnější pro malé datové struktury. Struktury obvykle ukládají data, která nemají být upravena po vytvoření struktury. Typy záznamů jsou datové struktury s dalšími syntetizovanými členy kompilátoru. Záznamy obvykle ukládají data, která nemají být změněna po vytvoření objektu.
Typy hodnot
Typy hodnot jsou odvozeny od System.ValueType, které jsou odvozeny z System.Object. Typy, které jsou odvozeny ze System.ValueType, mají speciální chování v CLR. Proměnné typu hodnoty přímo obsahují jejich hodnoty. Paměť pro strukturu je přidělena přímo v kontextu, kde je proměnná deklarována. Pro proměnné typu hodnota neexistuje žádné samostatné přidělení haldy ani režie uvolňování paměti. Můžete deklarovat record struct
typy, které jsou typy hodnot, a zahrnout syntetizované členy pro záznamy.
Existují dvě kategorie hodnotových typů: struct
a enum
.
Předdefinované číselné typy jsou struktury a mají pole a metody, ke kterým máte přístup:
// constant field on type byte.
byte b = byte.MaxValue;
Deklarujete a přiřadíte jim hodnoty, jako by to byly jednoduché neagregační typy:
byte num = 0xA;
int i = 5;
char c = 'Z';
Typy hodnot jsou zapečetěné. Typ nelze odvodit z žádného typu hodnoty, například System.Int32. Nelze definovat strukturu, která má dědit z jakékoli uživatelem definované třídy nebo struktury, protože struktura může dědit pouze z System.ValueType. Struktura však může implementovat jedno nebo více rozhraní. Typ struktury můžete přetypovat na libovolný typ rozhraní, který implementuje. Operace zabalení způsobí, že struktura bude uvnitř referenčního typu objektu na spravované haldě. Operace boxování probíhají, když předáte hodnotový typ metodě, která přijímá System.Object nebo jakýkoli typ rozhraní jako vstupní parametr. Další informace naleznete v tématu Boxing and Unboxing.
Pomocí klíčového slova struktury vytvoříte vlastní typy hodnot. Struktura se obvykle používá jako kontejner pro malou sadu souvisejících proměnných, jak je znázorněno v následujícím příkladu:
public struct Coords
{
public int x, y;
public Coords(int p1, int p2)
{
x = p1;
y = p2;
}
}
Další informace o strukturách naleznete v tématu Typy struktur. Další informace o typech hodnot naleznete v tématu Typy hodnot.
Další kategorie hodnotových typů je enum
. Výčet definuje sadu pojmenovaných integrálních konstant. Například System.IO.FileMode výčet v knihovně tříd .NET obsahuje sadu pojmenovaných konstantních celých čísel, které určují, jak má být soubor otevřen. Definuje se, jak je znázorněno v následujícím příkladu:
public enum FileMode
{
CreateNew = 1,
Create = 2,
Open = 3,
OpenOrCreate = 4,
Truncate = 5,
Append = 6,
}
Konstanta System.IO.FileMode.Create má hodnotu 2. Název je ale mnohem smysluplnější pro lidi, kteří čtou zdrojový kód, a proto je lepší místo konstantních literálových čísel použít výčty. Další informace najdete v tématu System.IO.FileMode.
Všechny výčty dědí z System.Enum, který dědí z System.ValueType. Všechna pravidla, která platí pro struktury, platí také pro výčty. Další informace o výčtech naleznete v tématu Výčtové typy.
Typy odkazů
Typ definovaný jako class
, , record
delegate
, pole nebo interface
je reference type
.
Když deklarujete proměnnou reference type
, obsahuje hodnotu null
, dokud ji nepřiřadíte s instancí tohoto typu nebo ji vytvoříte pomocí operátoru new
. Vytvoření a přiřazení třídy je znázorněno v následujícím příkladu:
MyClass myClass = new MyClass();
MyClass myClass2 = myClass;
Pomocí operátoru interface
nelze přímo vytvořit instanci new
. Místo toho vytvořte a přiřaďte instanci třídy, která implementuje rozhraní. Podívejte se na následující příklad:
MyClass myClass = new MyClass();
// Declare and assign using an existing value.
IMyInterface myInterface = myClass;
// Or create and assign a value in a single statement.
IMyInterface myInterface2 = new MyClass();
Při vytváření objektu je paměť přidělena na spravované haldě. Proměnná obsahuje pouze odkaz na umístění objektu. Typy v rámci spravované haldy vyžadují režii jak při jejich přidělení, tak při jejich uvolnění. Uvolňování paměti je funkce automatické správy paměti MODULU CLR, která provádí relamaci. Uvolňování paměti je ale také vysoce optimalizované a ve většině scénářů nevytváří problém s výkonem. Další informace o uvolňování paměti viz Automatická správa paměti.
Všechna pole jsou odkazové typy, i když jsou jejich prvky typy hodnot. Pole se implicitně odvozují z třídy System.Array. Deklarujete a používáte je se zjednodušenou syntaxí, kterou poskytuje jazyk C#, jak je znázorněno v následujícím příkladu:
// 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;
Odkazové typy plně podporují dědičnost. Při vytváření třídy můžete dědit z jakéhokoli jiného rozhraní nebo třídy, která není definována jako zapečetěná. Ostatní třídy můžou dědit z vaší třídy a přepsat virtuální metody. Další informace o tom, jak vytvořit vlastní třídy, naleznete v tématu Třídy, struktury a záznamy. Další informace o dědičnosti a virtuálních metodách naleznete v tématu Dědičnost.
Typy hodnot literálů
V jazyce C# literálové hodnoty přijímají typ z kompilátoru. Způsob zadávání číselného literálu můžete určit tak, že na konec čísla připojíte písmeno. Chcete-li například určit, že hodnota 4.56
by měla být považována float
za , připojte za číslo "f" nebo "F": 4.56f
. Pokud není připojeno žádné písmeno, kompilátor odvodí typ literálu. Další informace o tom, které typy lze specifikovat pomocí písmenových přípon, naleznete v tématech Integrální číselné typy a Číselné typy s pohyblivou řádovou čárkou.
Protože literály jsou zadány a všechny typy jsou odvozeny nakonec z System.Object, můžete psát a kompilovat kód, například následující kód:
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);
Obecné typy
Typ lze deklarovat pomocí jednoho nebo více parametrů typu , které slouží jako zástupný symbol pro skutečný typ ( konkrétní typ). Klientský kód poskytuje konkrétní typ při vytváření instance typu. Takové typy se nazývají obecné typy. Například typ System.Collections.Generic.List<T> .NET má jeden parametr typu, který podle konvence má název T
. Při vytváření instance typu zadáte typ objektů, které seznam obsahuje, string
například:
List<string> stringList = new List<string>();
stringList.Add("String example");
// compile time error adding a type other than a string:
stringList.Add(4);
Použití parametru typu umožňuje opakovaně použít stejnou třídu pro uložení jakéhokoli typu elementu, aniž by bylo nutné převést každý prvek na objekt. Obecné třídy kolekce se nazývají kolekce silného typu , protože kompilátor zná konkrétní typ prvků kolekce a může vyvolat chybu v době kompilace, pokud se například pokusíte přidat celé číslo k objektu stringList
v předchozím příkladu. Další informace najdete v tématu Obecné typy.
Implicitní typy, anonymní typy a typy hodnot s možnou hodnotou null
Pomocí klíčového var
slova můžete implicitně zadat místní proměnnou (ale ne členy třídy). Proměnná stále přijímá typ v době kompilace, ale typ je poskytován kompilátorem. Další informace naleznete v tématu Implicitně typované místní proměnné.
Není vhodné vytvořit pojmenovaný typ pro jednoduché sady souvisejících hodnot, které nechcete ukládat ani předávat mimo hranice metody. Pro tento účel můžete vytvořit anonymní typy . Další informace naleznete v tématu Anonymní typy.
Běžné typy hodnot nemohou mít hodnotu null
. Typy hodnot s možnou hodnotou null však můžete vytvořit tak, že za ?
tento typ připojíte. Jedná se například o typ, int?
který může mít také hodnotu int
.null
Typy hodnot s možnou hodnotou null jsou instance obecného typu System.Nullable<T>struktury . Typy hodnot, které mohou mít hodnotu null, jsou užitečné zejména při předávání dat do az databází, kde číselné hodnoty mohou být null
. Další informace naleznete v tématu nulovatelné typy hodnot.
Typ kompilace a typ běhu
Proměnná může mít různé typy kompilace a doby běhu. Typ kompilace je deklarovaný nebo odvozený typ proměnné ve zdrojovém kódu. Typ běhu je typ instance odkazované danou proměnnou. Tyto dva typy jsou často stejné, jako v následujícím příkladu:
string message = "This is a string of characters";
V jiných případech se typ doby kompilace liší, jak je znázorněno v následujících dvou příkladech:
object anotherMessage = "This is another string of characters";
IEnumerable<char> someCharacters = "abcdefghijklmnopqrstuvwxyz";
V obou předchozích příkladech je typ běhu typu string
. Typ času kompilace je object
na prvním řádku a IEnumerable<char>
ve druhém.
Pokud se oba typy pro proměnnou liší, je důležité pochopit, kdy se používá typ kompilace a typ běhu. Typ času kompilace určuje všechny akce prováděné kompilátorem. Tyto akce kompilátoru zahrnují rozlišení volání metod, řešení přetížení a implicitní i explicitní konverze. Typ doby běhu určuje všechny akce, které jsou vyřešeny za běhu. Tyto akce za běhu zahrnují odesílání volání virtuálních metod, vyhodnocování is
a switch
výrazů a další rozhraní API pro testování typů. Abyste lépe pochopili, jak váš kód komunikuje s typy, rozpoznáte, která akce se vztahuje na který typ.
Související oddíly
Další informace najdete v následujících článcích:
Specifikace jazyka C#
Další informace najdete ve specifikaci jazyka C#. Specifikace jazyka je konečným zdrojem syntaxe a použití jazyka C#.