Lekce 4 - Typový systém podruhé: Datové typy v C# .NET
V předešlém cvičení, Řešené úlohy k 1.-3. lekci C# .NET, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Nyní se na datové typy podíváme více zblízka a vysvětlíme si, kdy jaký použít. Dnešní lekce bude hodně teoretická, ale o to více bude praktická ta příští. Na konci si vytvoříme pár jednoduchých ukázek.
C# rozeznává dva druhy datových typů, hodnotové a referenční.
Hodnotové datové typy
Proměnné hodnotového datového typu si dokážeme jednoduše představit. Může se jednat např. o číslo nebo znak. V paměti je jednoduše uložena přímo hodnota a my k této hodnotě můžeme z programu přímo přistupovat. Slovo přímo jsem tolikrát nepoužil jen náhodou. V tomto C# kurzu se budeme věnovat výhradně těmto proměnným.
Celočíselné datové typy
Podívejme se nyní na tabulku všech vestavěných celočíselných
datových typů v .NET, všimněte si typu int
, který již známe
zminula.
Datový typ | Rozsah | Velikost | .NET typ |
---|---|---|---|
sbyte | -128 až 127 | 8 bitů | System.SByte |
byte | 0 až 255 | 8 bitů | System.Byte |
short | -32 768 až 32 767 | 16 bitů | System.Int16 |
ushort | 0 až 65 535 | 16 bitů | System.UInt16 |
int | -2 147 483 648 až 2 147 483 647 | 32 bitů | System.Int32 |
uint | 0 až 4 294 967 295 | 32 bitů | System.UInt32 |
long | -9 223 372 036 854 775 808 až 9 223 372 036 854 775 807 | 64 bitů | System.Int64 |
ulong | 0 až 18 446 744 073 709 551 615 | 64 bitů | System.UInt64 |
Všechna ta šílené čísla z této tabulky si pamatovat nemusíte, téměř vždy vám pomůže ve Visual Studiu nástroj IntelliSense, který když budete psát ten datový typ a počkáte ukáže nad ním bublinu:

Případně v dokumentaci dodávané k Visual studiu to najdete podrobněji. Do dokumentace se dostanete, když napíšete konkrétní datový typ, označíte jej a stisknete F1.
Asi vás napadá otázka, proč máme tolik možných typů pro uložení
čísla. Odpověď je prostá, záleží na jeho velikosti. Čím větší
číslo, tím více spotřebuje paměti. Pro věk uživatele tedy zvolíme
byte
, protože se jistě nedožije více, než 255 let. Představte
si databázi milionu uživatelů nějakého systému, když zvolíme místo byte
int
, bude zabírat 4x více místa. Naopak když budeme mít funkci
k výpočtu faktoriálu, stěží nám bude stačit rozsah integeru a použijeme
long
.
Všimněte si, že některé typy začínají na u
. Jsou
téměř stejné, jako jejich dvojníci bez u
, jen neumožňují
záporné hodnoty a tím pádem na kladnou část mohou uložit 2x vyšší
hodnotu. Těmto typům se říká unsigned, klasickým
signed.
.NET typ je název dané struktury v .NET knihovnách. My používáme tzv. aliasy, aby byla práce jednodušší, ve skutečnosti si C# kód:
int a = 10;
přebere jako:
System.Int32 a = 10;
My budeme samozřejmě používat aliasy, od toho tam jsou
Nad výběrem datového typu nemusíte moc přemýšlet a většinou se
používá jednoduše int
. Typ řešte pouze v případě, když
jsou proměnné v nějakém poli (obecně kolekci) a je jich tedy více, potom
se vyplatí zabývat se paměťovými nároky. Tabulky sem dávám spíše pro
úplnost. Mezi typy samozřejmě funguje již zmíněná implicitní konverze,
tedy můžeme přímo přiřadit int
do proměnné typu
long
a podobně, aniž bychom něco konvertovali.
Desetinná čísla
U desetinných čísel je situace poněkud jednodušší, máme na výběr
pouze dva datové typy. Samozřejmě se liší opět v rozsahu hodnoty, dále
však ještě v přesnosti (vlastně počtu des. míst). Typ double
má již dle názvu dvojnásobnou přesnost oproti float
.
Datový typ | Rozsah | Přesnost | .NET typ |
---|---|---|---|
float | +-1.5 * 10−45 až +-3.4 * 1038 | 7 čísel | System.Single |
double | +-5.0 * 10−324 až +-1.7 * 10308 | 15-16 čísel | System.Double |
Vzhledem k tomu, že desetinná čísla jsou v počítači uložena ve dvojkové soustavě, dochází k určité ztrátě přesnosti. Odchylka je sice téměř zanedbatelná, nicméně když budete programovat např. finanční systém, nepoužívejte tyto dat. typy pro uchování peněz, mohlo by dojít k malým odchylkám.
Když do float
u chceme dosadit přímo ve zdrojovém kódu,
musíme použít sufix F
, u double
sufix
D
(u double ho můžeme vypustit, jelikož je výchozí desetinný
typ):
float f = 3.14F; double d = 2.72;
Jako desetinný separátor používáme ve zdrojovém kódu vždy tečku, nehledě na to, jaké máme ve Windows regionální nastavení.
Další vestavěné datové typy
Podívejme se na další datové typy, které nám .NET nabízí:
Datový typ | Rozsah | Velikost/Přesnost | .NET typ |
---|---|---|---|
char | U+0000 až U+ffff | 16 bitů | System.Char |
decimal | +-1.0 * 10−28 až +-7.9 * 1028 | 28-29 čísel | System.Decimal |
bool | true nebo false | 8 bitů | System.Boolean |
char
Char nám reprezentuje jeden znak, na rozdíl od typu string
,
který reprezentoval celý řetězec char
ů. Znaky v C# píšeme do
apostrofů. Apostrof '
píšeme na české klávesnici pomocí
Shift a klávesy vedle Enter (u některých klávesnic je
to klávesa nad Enter, u jiných před ním):

Deklarujme si tedy proměnnou typu char
, obsahující nějaký
znak:
char c = 'A';
Typ char
patří v podstatě do celočíselných proměnných
(obsahuje číselný kód znaku), ale přišlo mi logičtější uvést ho zde.
Typ char
nám vrací např. metoda
Console.ReadKey()
.
decimal
Typ decimal
řeší problém ukládání desetinných čísel v
binární podobě, ukládá totiž číslo vnitřně podobně jako text.
Používá se tedy pro uchování peněžních hodnot. Ke všem dalším
matematickým operacím s des. čísly použijeme float
nebo
double
. K zápisu decimal
hodnoty opět používáme
sufix, m
:
decimal m = 3.14159265358979323846m;
bool
Datový typ bool
nabývá dvou hodnot: true
(pravda) a false
(nepravda). Budeme ho používat zejména tehdy,
až se dostaneme k podmínkám. Do proměnné typu bool
lze uložit
jak přímo hodnotu true
/false
, tak i logický výraz.
Zkusme si jednoduchý příklad:
{CSHARP_CONSOLE}
bool b = false;
bool vyraz = (15 > 5);
Console.WriteLine(b);
Console.WriteLine(vyraz);
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikace
False
True
Výrazy píšeme do závorek. Vidíme, že výraz nabývá hodnoty
true
(pravda), protože 15
je opravdu větší než
5
. Od výrazů je to jen krok k podmínkám, na ně se podíváme
příště.
Referenční datové typy
K referenčním typům se dostaneme až u objektově orientovaného
programování, kde si také vysvětlíme zásadní rozdíly. Zatím budeme
pracovat jen s tak jednoduchými typy, že rozdíl nepoznáme. Spokojíme se s
tím, že referenční typy jsou složitější, než ty hodnotové. Jeden
takový typ již známe, je jím string
. Možná vás napadá, že
string
nemá nijak omezenou délku, je to tím, že s
referenčními typy se v paměti pracuje jinak.
Typ string
má na sobě řadu opravdu užitečných metod.
Některé si teď probereme a vyzkoušíme:
String
StartsWith()
, EndsWith()
a
Contains()
Můžeme se jednoduše zeptat, zda řetězec začíná, končí nebo zda
obsahuje určitý podřetězec (substring). Podřetězcem myslíme část
původního řetězce. Všechny tyto metody budou jako parametr brát
samozřejmě podřetězec a vracet hodnoty typu bool
(true
/false
). Zatím na výstup neumíme reagovat, ale
pojďme si ho alespoň vypsat:
{CSHARP_CONSOLE}
string s = "Krokonosohroch";
Console.WriteLine(s.StartsWith("krok"));
Console.WriteLine(s.EndsWith("hroch"));
Console.WriteLine(s.Contains("nos"));
Console.WriteLine(s.Contains("roh"));
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikace
False
True
True
False
Vidíme, že vše funguje podle očekávání. První výraz samozřejmě neprošel díky tomu, že řetězec ve skutečnosti začíná velkým písmenem.
ToUpper()
a ToLower()
Rozlišování velkých a malých písmen může být někdy na obtíž.
Mnohdy se budeme potřebovat zeptat na přítomnost podřetězce tak, aby
nezáleželo na velikosti písmen. Situaci můžeme vyřešit pomocí metod
ToUpper()
a ToLower()
, které vrací řetězec ve
velkých a v malých písmenech. Uveďme si reálnější příklad než je
Krokonosohroch. Budeme mít v proměnné řádek konfiguračního souboru,
který psal uživatel. Jelikož se na vstupy od uživatelů nelze spolehnout,
musíme se snažit eliminovat možné chyby, zde např. s velkými písmeny.
{CSHARP_CONSOLE}
string konfig = "Fullscreen shaDows autosave";
konfig = konfig.ToLower();
Console.WriteLine("Poběží hra ve fullscreenu?");
Console.WriteLine(konfig.Contains("fullscreen"));
Console.WriteLine("Budou zapnuté stíny?");
Console.WriteLine(konfig.Contains("shadows"));
Console.WriteLine("Přeje si hráč vypnout zvuk?");
Console.WriteLine(konfig.Contains("nosound"));
Console.WriteLine("Přeje si hráč hru automaticky ukládat?");
Console.WriteLine(konfig.Contains("autosave"));
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikace
Poběží hra ve fullscreenu?
True
Budou zapnuté stíny?
True
Přeje si hráč vypnout zvuk?
False
Přeje si hráč hru automaticky ukládat?
True
Vidíme, že jsme schopni zjistit přítomnost jednotlivých slov v řetězci tak, že si nejprve řetězec převedeme celý na malá písmena (nebo na velká) a potom kontrolujeme přítomnost slova jen malými (nebo velkými) písmeny. Takhle by mimochodem mohlo opravdu vypadat jednoduché zpracování nějakého konfiguračního skriptu.
Trim()
, TrimStart()
a TrimEnd()
Problémem ve vstupech od uživatele může být i diakritika. C# ale naštěstí pracuje plně v UTF-8, nestane se nám tedy, že by se diakritika nějak zkomolila. Další nástrahou mohou být mezery a obecně všechny tzv. bílé znaky, které nejsou vidět, ale mohou nám uškodit. Obecně může být dobré tzv. trimovat všechny vstupy od uživatele, můžeme trimovat buď okolo celého řetězce nebo jen bílé znaky před ním a za ním. Prozradím, že při parsovacích funkcích C# trimuje zadaný řetězec automaticky, než s ním začne pracovat. Odstraněny jsou pouze neviditelné znaky okolo řetězce, např. mezery mezi slovy zůstanou. Zkuste si v následující aplikaci před číslo a za číslo zadat několik mezer:
{CSHARP_CONSOLE}
Console.WriteLine("Zadejte číslo:");
string s = Console.ReadLine();
Console.WriteLine("Zadal jste text: " + s);
Console.WriteLine("Text po funkci trim: " + s.Trim());
int a = int.Parse(s);
Console.WriteLine("Převedl jsem zadaný text na číslo parsováním, zadal jste: " + a);
Console.ReadKey();
{/CSHARP_CONSOLE}
Replace()
Asi nejdůležitější metodou na string
u je nahrazení
určité jeho části jiným textem. Jako parametry zadáme dva podřetězce,
jeden co chceme nahrazovat a druhý ten, kterým to chceme nahradit. Metoda
vrátí nový string
, ve kterém proběhlo nahrazení. Když daný
podřetězec metoda nenajde, vrátí původní řetězec.
V následující ukázce použijeme v textu mřížku #
. Ta se
na české klávesnici píše pomocí Pravého Alt a klávesy
X:

A teď si již zkusme nahradit podřetězec metodou
Replace()
:
{CSHARP_CONSOLE}
string s = "Java je nejlepší!";
s = s.Replace("Java", "C#");
Console.WriteLine(s);
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikace
C# je nejlepší!
Format()
Format()
je velmi užitečná metoda, která nám umožňuje
vkládat do samotného textového řetězce zástupné značky. Ty jsou
reprezentovány jako číslo ve složených závorkách, prvním číslem je
0
. Jako další parametry metody následují v tomto pořadí
hodnoty, které se mají do textu místo značek vložit. Všimněte si, že se
metoda nevolá na konkrétní proměnné (přesněji instanci, viz další
lekce), ale přímo na typu string
.
Složené závorky (levou a pravou) píšeme na české klávesnici pomocí Pravého Alt a klávesy B pro levou, resp. N pro pravou:

Zkusme si tedy použít metodu Format()
pro vložení několika
proměnných do proměnné typu string
:
{CSHARP_CONSOLE}
int a = 10;
int b = 20;
int c = a + b;
string s = string.Format("Když sečteme {0} a {1}, dostaneme {2}", a, b, c);
Console.WriteLine(s);
Console.ReadKey();
{/CSHARP_CONSOLE}
Výstup programu:
Konzolová aplikace
Když sečteme 10 a 20, dostaneme 30
Konzole sama umí přijímat text v takovémto formátu, můžeme tedy napsat:
{CSHARP_CONSOLE}
int a = 10;
int b = 20;
int c = a + b;
Console.WriteLine("Když sečteme {0} a {1}, dostaneme {2}", a, b, c);
Console.ReadKey();
{/CSHARP_CONSOLE}
Toto je velmi užitečná a přehledná cesta, jak sestavovat řetězce, a
určitě se ji vyplatí mnohdy použít místo běžné konkatenace pomocí
operátoru +
, pokud nebazírujeme na vysoké rychlosti.
Interpolace řetězců
Pokud chceme do řetězce v C# na určitá místa vložit nějaké
proměnné, můžeme kromě zástupných znaků {0}
apod. zapsat
proměnné i přímo do řetězce obalením názvu proměnné do složených
závorek. Takový řetězec poté musíme předsadit znakem $
, aby
C# věděl, že ve složených závorkách má očekávat proměnné a nejedná
se o běžný text:
int a = 10; int b = 20; int c = a + b; Console.WriteLine($"Když sečteme {a} a {b}, dostaneme {c}"); Console.ReadKey();
Výstup programu:
Konzolová aplikace
Když sečteme 10 a 20, dostaneme 30
Tato funkcionalita je podporována pouze v nových verzích C# a zatím ji nepodporuje náš online kompiler.
Podobně můžeme místo proměnné vložit i výraz. Takováto funkcionalita se nám často hodí při výpisu. Zkusme si rovnou i sečíst čísla přímo ve výrazu:
int a = 10; int b = 20; Console.WriteLine($"Když sečteme {a} a {b}, dostaneme {a + b}"); Console.ReadKey();
Výstup programu:
Konzolová aplikace
Když sečteme 10 a 20, dostaneme 30
PadLeft()
a PadRight()
Jako poslední si zmíníme metody, které nám k textu naopak mezery
přidají K čemu to je
dobré? Představte si, že máme 100 proměnných a budeme je chtít
uspořádat do tabulky. Text upravíme pomocí metody
PadRight()
s
parametrem šířky sloupce, tedy např. 20 znaků. Pokud bude mít text jen 12
znaků, vypíše se před něj 8 mezer, aby měl velikost 20. Obdobně metoda
PadLeft()
by vypsala 8 mezer za něj. Jelikož nemáme znalosti k
vytvoření takové tabulky, budeme si metody jen pamatovat a vyzkoušíme si je
dále v C# kurzu.
Vlastnost Length
Poslední, ale nejdůležitější vlastnost (pozor, ne metoda) je
Length
, tedy délka. Vrací celé číslo, které představuje
počet znaků v řetězci. Za vlastnosti nepíšeme závorky, protože nemají
parametry.
{CSHARP_CONSOLE}
Console.WriteLine("Zadejte vaše jméno:");
string jmeno = Console.ReadLine();
Console.WriteLine("Délka vašeho jména je: {0}", jmeno.Length);
Console.ReadKey();
{/CSHARP_CONSOLE}
Je toho ještě spoustu k vysvětlování a jsou další datové typy, které jsme neprobrali.
V příští lekci, Nejčastější chyby C# začátečníků - Umíš pojmenovat proměnné?, si ukážeme nejčastější chyby začátečníků v C# .NET ohledně pojmenování proměnných.
Komentáře


Zobrazeno 10 zpráv z 116. Zobrazit vše