Základní elementy VB.NET a C#

2. díl - Základní elementy VB.NET a C#

Tomáš Herceg       18.04.2009       C#, VB.NET, .NET       24604 zobrazení

V tomto dílu si popíšeme základní prvky jazyků VB.NET a C#, stručně projedeme jejich syntaxi a ukážeme si vestavěné základní datové typy.

V minulém díle jsme si poměrně obšírně vysvětlili, co to .NET Framework vlastně je a jak probíhá kompilace aplikace napsané v .NET. Dnes si popíšeme základní konstrukce jazyků VB.NET a C#, ukážeme si některé rozdíly, které v těchto jazycích máme. Ještě před tím si ale něco povíme o .NET assemblies.

Struktura .NET assembly

Ať už budeme programovat okenní nebo konzolovou aplikaci, web či nějakou knihovnu, výsledkem bude jedna či více .NET assemblies, a to s příponou dll či exe. Co vlastně taková assembly obsahuje?

Single-file assembly  Multifile assembly

Tyto obrázky jsem převzal z MSDN, protože jsou výstižné. Assembly může být buď single-file (první obrázek), kdy je vše pohromadě, nebo multifile (druhý obrázek), kde assembly tvoří několik souborů. Je nutné si uvědomit, že v druhém případě soubory Util.netmodule a Graphic.bmp nejsou součástí souboru assembly, ale jsou to oddělené soubory, které se k assembly propojují pouze informací v manifestu. Visual Studio standardně vytváří single-file assemblies.

Manifest

Manifest obsahuje mnoho důležitých informací o samotné assembly a jejím obsahu, jmenovitě jméno assembly, číslo verze, výchozí kulturu (jazykové a národní nastavení), strong name (vysvětlíme později), seznam souborů patřících k assembly, informace o datových typech a implementacích jejich metod a informace o všech referencovaných assembly.

Referencované assemblies jsou takové assemblies, které obsahují datové typy, které naše assembly používá, ale sama je nedeklaruje. Určitě sem patří například základní knihovny .NET Frameworku, které obsahují definice vestavěných datových typů a které určitě každá naše assembly bude používat, proto potřebuje mít referencované knihovny, kde jsou tyto typy definovány.

Moduly

Modul je část assembly, která obsahuje kód a definice datových typů. Modul je víceméně zkompilovaný jeden soubor kódu, analogie např. objektových modulů v C/C++. Assembly vznikne slinkováním modulů dohromady linkerem. Samotný modul si relativně jednoduše můžete vytvořit pomocí řádkového kompilátoru csc či vbc, stačí mu dát nějaký přepínač (kompilátory najdete ve složce C:\Windows\Microsoft.NET\Framework\v2.0.50727) a slinkovat moduly dohromady můžete pomocí nástroje al. To je spíš jen tak pro zajímavost, v praxi se o to nemusíme starat, vše za nás udělá vývojové prostředí Visual Studio

Poznámka: Pokud znáte jazyk Visual Basic, ten má také moduly, což byly ve staré verzi jakési kolekce globálních funkcí, ve VB.NET je modul statická třída. Toto jsou však trochu jiné moduly.

Strong name

Assembly může mít tzv. strong name. Ten je tvořen z názvu assembly, čísla verze, kultury, veřejného klíče a digitálního podpisu. Strong name může vypadat třeba takto:

System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089

Jaké jsou výhody a k čemu to je? V první řadě jde o bezpečnost – assembly je podepsaná pomocí privátního klíče, který má jen vydavatel dané assembly a nikdo jiný. Pokud tedy vaše assembly používá nějakou cizí knihovnu a nareferencujete ji pomocí jejího strong name, zařídí se tím, že se může použít pouze ta konkrétní knihovna v dané konkrétní verzi. Nikdo nemůže podvrhnout svoji vlastní knihovnu, měla by jiný digitální podpis; ani samozřejmě nejde existující a správnou knihovnu změnit, pokud by něco takového nastalo, runtime jednoduše vyhodí chybu, protože digitální podpis nebude souhlasit s obsahem assembly. Strong name assembly jednoznačně identifikuje; pokud mají dvě assemblies silný název různý, nejsou stejné.

Navíc je možné mít na jednom stroji stejné knihovny různých verzí, díky silným názvům je používaná verze knihovny přesně definovávna. Strong names se používají mimo jiné právě v manifestu pro určení referencovaných assemblies.

Programovací jazyky

Nad .NET Frameworkem existuje mnoho různých programovacích jazyků, zdaleka nejpoužívanější jsou ale Visual Basic .NET a C#. Tyto dva jazyky jsou si velmi podobné, přestože mají dost odlišný původ.

Visual Basic .NET

Jazyk BASIC vznikl zhruba v 60. letech minulého století a byl určen především pro výuku programování. Tento starý jazyk neměl funkce ani procedury, řádky se číslovaly a vzniklo mnoho jeho různých větví, z nichž žádná se moc neprosadila. Velké popularity se dočkal QBasic, který byl zaintegrován v MS-DOSu, a který umožňoval psát strukturovaně – uměl procedury, funkce, struktury a datové typy. Pořád to ale byl jazyk interpretovaný, což vyřešil až QuickBasic. Programy v QuickBasicu ale moc “quick” nikdy nebyly.

S nástupem Windows se objevil Visual Basic. Napsat okenní aplikaci pro Windows v C/C++ nebylo právě jednoduché, zatímco Visual Basic umožnil díky svému vývojovému prostředí “naklikat” uživatelské rozhraní a dopsat kód. O mnoho let později tuto myšlenku převzala jiná vývojová prostředí, například Borland Delphi.

Poslední verzí klasického Visual Basicu byla verze Visual Basic 6 z roku 1998. Visual Basic jako takový již docela zaostával za konkurencí, nenabízel mnoho výhod a nebyl právě nejrychlejší. Dosáhl i tak ale velké obliby (zvláště na západě) a mnoho aplikací bylo napsáno právě v něm. Podporoval částečně objektově orientované programování (i když moc možností tam nebylo), cílený byl především na databázové aplikace.

S nástupem platformy .NET se Microsoft rozhodl Visual Basic vzkřísit a vytvořil verzi Visual Basic 7 (což je verze jazyka, ne vývojového prostředí). Tento jazyk přinesl mnoho novinek, mnoho věcí se změnilo. Konečně se v jazyce objevila pořádná a kompletní podpora objektově orientovaného programování, díky .NETu jazyk dostal nepřeberné množství knihovních funkcí a zachována byla samozřejmě i kompatibilita s COM a Windows API voláními. Programy napsané ve VB.NET mohou být díky .NET Frameworku rychlejší, samozřejmě ale záleží na tom, jak je aplikace napsána. V současné době je aktuální verzí jazyka Visual Basic 9, která mimo generických typů a jiných vylepšení podporuje technologii LINQ.

Syntaxe jazyka Visual Basic

Visual Basic vychází z jazyka Basic, který byl určen pro výukové účely. Jeho syntaxe je svým způsobem ojedinělá a kvůli jednoduchosti a srozumitelnosti obsahuje mnoho klíčových slov, začátečníci se v ní výrazně lépe orientují, je to taková skoro strojová angličtina. Všechny názvy jsou case-insensitive, což znamená, že nezáleží na velikosti písmen v klíčových slovech, názvech proměnných, metod a typů.

Konec řádku je signifikantní znak, používá se k oddělování příkazů. Na rozdíl od většiny jazyků na konci příkazů nejsou středníky. Pokud chceme na jeden řádek dát více příkazů, můžeme, stačí je oddělit dvojtečkou. Pokud naopak chceme rozdělit příkaz do více řádků, použijeme sekvenci znaků mezera podtržítko. V nové verzi jazyka Visual Basic 10, která se chystá, se tato sekvence může vynechat, kompilátor podle kontextu pozná, jestli se jedná o konec řádku, nebo o jeden řádek rozdělený na více částí (kdy je možné řádky dělit je přesně definováno ve specifikaci a pravidla jsou to celkem jednoduchá a intuitivní).

Komentáře existují pouze jednořádkové, začínají znakem apostrof a končí společně s koncem řádku.

C#

Na rozdíl od Visual Basicu je C# jazykem velmi mladým a jeho historie je prakticky stejně dlouhá jako historie .NET Frameworku. Tento jazyk byl speciálně navržen pro .NET Framework a i když to tak ze začátku nevypadalo, stal se velmi brzy daleko oblíbenějším než Visual Basic. Má syntaxi velmi podobnou jazykům C/C++ a Java, takže je na něj pro stávající vývojáře v těchto technologiích velmi snadné přejít, nemusí se učit novou syntaxi, protože je velmi podobná.

Syntaxe jazyka C#

Jazyk C# je case-sensitive, záleží v něm na velikosti písmen. Konec řádku není signifikantním znakem, k oddělování příkazů se používají středníky.

Komentáře existují jednořádkové (začínají sekvencí dvou lomítek //) anebo víceřádkové (uzavřené mezi skupinami /* a */).

Poznámka: Protože nad .NET Frameworkem je kromě VB.NET i mnoho jiných jazyků, které nerozlišují velikosti písmen, je velmi vhodné i v case-sensitive jazycích nevytvářet názvy lišící se pouze velikostí písmen; rozhodně alespoň v případě, že jde o názvy, které jsou viditelné navenek a které se budou z vnějšku používat.

Struktura kódu uvnitř assembly

V jazycích VB.NET a C# nejsou globální funkce ani proměnné. Veškeré metody (tedy funkce a procedury) a proměnné musí být uzavřeny uvnitř nějakého datového typu. Datový typem myslíme jednu z těchto položek (ne ve všech mohou být metody a proměnné):

  • třída
  • rozhraní
  • struktura
  • výčtový typ (enum)
  • delegát
  • vestavěný typ 

Namespaces

Každý typ je zařazen do nějakého jmenného prostoru (namespace). Jmenné prostory tvoří hierarchické rozdělení typů podle jejich funkce a oblasti použití. Například ve jmenném prostoru System se nachází základní datové typy (třeba Integer, String, DateTime) a třídy (např. třída Math obsahující matematické funkce atp.). Vše, co se týká grafiky, se nachází ve jmenném prostoru System.Drawing; vše, co se týká okenních aplikací, je ve jmenném prostoru System.Windows.Forms a podobně.

Pokud datový typ nezařadíte do žádného jmenného prostoru, automaticky bude zařazen do výchozího namespace v assembly (někdy se mu říká globální namespace).

Kód v jazyce Visual Basic .NET

Namespace VbNet.Tutorials

End Namespace
Kód v jazyce C#
namespace VbNet.Tutorials
{

}

Všechny datové typy, které uvedeme dovnitř sekce namespace, budou zařazeny ve jmenném prostoru VbNet.Tutorials. V kódu můžeme používat všechny datové typy, které jsou ve stejném jmenném prostoru, nebo které jsou ve výchozím jmenném prostoru.

Pokud tedy uvnitř našeho jmenného prostoru nadefinujeme třídy A a třídy B, budeme se ze třídy A odvolávat na třídu B pouhým napsáním názvu třídy, tedy B. Pokud chceme použít typ z jiného jmenného prostoru, musíme se na něj odvolat celou cestou tohoto prostoru, například VbNet.C, pokud by třída C byla ve jmenném prostoru VbNet.

Psát celý název typu včetně jmenného prostoru je samozřejmě zdlouhavé, proto máme možnost si jmenné prostory naimportovat. To se dělá takto pomocí klíčového slova Imports resp. using, které platí pro celý soubor a píše se hned na začátek.

Kód v jazyce Visual Basic .NET
Imports VbNet

Namespace VbNet.Tutorials

End Namespace
Kód v jazyce C#
using VbNet;

namespace VbNet.Tutorials
{

}

Pokud jmenný prostor VbNet naimportujeme, můžeme v celém souboru používat typy z tohoto jmenného prostoru, aniž bychom museli uvádět jejich cestu; stačí prostě použít název datového typu.

Základní syntaktické konstrukce

Základní datové typy

V této tabulce máme základní vestavěné datové typy, které nám .NET framework nabízí.

VB.NET C# .NET typ Velikost Popis
SByte sbyte System.SByte 8 bitů 8-bit celé číslo se znaménkem (-128 až 127)
Byte byte System.Byte 8 bitů 8-bit celé číslo bez znaménka (0 až 255)
Short short System.Int16 16 bitů 16-bit celé číslo se znaménkem (-2^15 až 2^15 - 1)
UShort ushort System.UInt16 16 bitů 16-bit celé číslo bez znaménka (0 - 2^16 – 1)
Integer int System.Int32 32 bitů 32-bit celé číslo se znaménkem (-2^31 až 2^31 – 1)
UInteger uint System.UInt32 32 bitů 32-bit celé číslo bez znaménka (0 - 2^32 – 1)
Long long System.Int64 64 bitů 64-bit celé číslo se znaménkem (-2^63 až 2^63 – 1)
ULong ulong System.UInt64 64 bitů 64-bit celé číslo bez znaménka (0 - 2^64 – 1)
Single float System.Single 32 bitů 32-bit desetinné číslo podle IEEE 754 (7-8 platných cifer)
Double double System.Double 64 bitů 64-bit desetinné číslo podle IEEE 754
Decimal decimal System.Decimal 128 bitů 128-bit desetinné číslo (96-bit celé číslo a pozice desetinné čárky; 29 platných číslic)
Boolean bool System.Boolean   hodnoty true / false
Char char System.Char 16 bitů 16-bit znak podle Unicode
- - System.IntPtr 32/64 bitů Pointer (kvůli práci s Windows API)
String string System.String   Textový řetězec (Unicode)

V jakémkoliv programovacím jazyce můžete pro datové typy použít název ze sloupce .NET typ, pokud si naimportujete jmenný prostor System, nemusíte uvádět celý název. V jazyce VB.NET můžete používat i názvy z 1. sloupce, v C# zase názvy z 2. sloupce (a také se to tak v drtivé většině případů píše, jsou to aliasy pro dané datové typy, aby se alespoň se základními typy pracovalo pohodlně).

Deklarace proměnných

Pokud chceme nadeklarovat proměnnou, musíme tak učinit uvnitř nějakého typu, například uvnitř struktury, třídy, případně uvnitř metody. Ve VB.NET používáme konstrukci Dim proměnná As typ, v C# konstrukci typ proměnná. Můžeme používat jak aliasy datového typu pro daný jazyk, tak i samozřejmě .NET názvy (druhý řádek).

Kód v jazyce Visual Basic .NET
Dim a As Integer
Dim b As System.Boolean
Kód v jazyce C#
int a;
System.Boolean b;

Názvy proměnných mohou obsahovat kromě číslic, písmen a podtržítka též různé národně specifické znaky, třeba písmena s háčky a čárkami, ovšem to bych nedoporučoval. Je to věc názoru, ale pokud člověk vidí anglická klíčová slova prokládaná českými výrazy s nabodeníčky, vypadá to přinejmenším nesourodě a nekonzistentně. Podle mě je vhodné pojmenovávat proměnné, metody, třídy a vše ostatní anglicky. Hlavní je ale mít jasné konvence a dělat to jakkoliv, ale všude stejně.

Poznámka: Ve starších verzích jazyka Visual Basic (6 a nižší) nebylo deklarování proměnných nutné. Pokud jste proměnnou nedeklarovali, použil se pro ni datový typ Variant, který měl poměrně značnou výkonnostní i paměťovou režii. To v .NET Frameworku není možné, je potřeba striktně definovat každou proměnnou, kterou používáme. Ve starém Visual Basicu bylo možné definovat datové typy proměnné i pomocí speciálních symbolů v názvu, například proměnná s$ byla automaticky typu String. Vřele doporučuji tento přežitek ještě ze starého BASICu nepoužívat, dnes se to obecně považuje za zastaralé a není to v souladu s obecnými zvyklostmi a konvencemi. Stejně taky byste neměli do názvů proměnných dávat prefixy ani suffixy naznačující datový typ. Není to nutné, ale je dobré dodržovat styl pojmenovávání proměnných konzistentní se zbytkem .NET Frameworku. Tato pravidla jsou pěkně popsána například v článku pana Ondřeje Linharta Konvence při psaní zdrojového kódu.

Deklarace metod

Metody mohou být umístěny uvnitř tříd či struktur, samozřejmě mohou mít parametry a návratovou hodnotu. Procedury se deklarují takto:

Kód v jazyce Visual Basic .NET
Sub Procedura(ByVal i As Integer, ByVal b As Boolean)

End Sub
Kód v jazyce C#
void Procedura(int i, bool b)
{

}

Procedury návratovou hodnotu nemají, ve VB.NET se to naznačuje klíčovým slovem Sub, v C# slovem void místo návratového typu. V závorce za názvem funkce (Funkce) je seznam parametrů a jejich datových typů. Ve VB.NET slovo ByVal není nutné psát, Visual Studio si jej tam doplní automaticky. Co ByVal znamená a jak se předávají argumenty hodnotou a referencí si vysvětlíme příště.

Funkce se deklarují velmi podobně (návratový typ je v C# před názvem funkce, ve VB.NET za seznamem argumentů):

Kód v jazyce Visual Basic .NET
Function Funkce(ByVal i As Integer, ByVal b As Boolean) As Integer
    Return 5
End Function
Kód v jazyce C#
int Funkce(int i, bool a)
{
    return 5;
}

K vracení hodnot z funkce se používá klíčové slovo return, za kterým následuje výraz určující návratovou hodnotu. Provedením příkazu return se ukončí i provádění metody, další příkazy za tímto řádkem se nespustí.

Klauzule return se dá použít i v procedurách bez uvedení návratové hodnoty k okamžitému ukončení provádění procedury.

Ve VB.NET můžeme vracet návratovou hodnotu z funkce i tak, že ji přiřadíme do názvu funkce. Tím se provádění funkce neukončí, ale návratová hodnota je již nastavena. Provádění funkce či procedury můžeme ukončit též příkazy Exit Function resp. Exit Sub.

Podmínky

Pro vytváření podmíněných bloků, používáme klíčové slovo If. Podmíněné bloky se liší trochu více jazyk od jazyka, proto pro každý jazyk následuje zvláštní popis.

Kód v jazyce Visual Basic .NET
            If podmínka Then
                blok_příkazů
            ElseIf podmínka Then
                blok_příkazů
            ElseIf podmínka Then
                blok_příkazů
            Else
                blok_příkazů
            End If

            If podmínka Then příkazy Else příkazy

Ve VB.NET máme dvě verze struktury podmínek – plnou a zkrácenou. Ve zkrácené verzi (poslední řádek v ukázce) podmínek je na místě příkazy jeden nebo více příkazů oddělených dvojtečkou. Větev Else je nepovinná.

V plné verzi je na místech podmínka nějaký výraz (viz dále) a na místech blok_příkazů je jeden nebo více příkazů (oddělené znakem konce řádku, případně dvojtečkou). Samozřejmě i klauzule If je příkaz, podmínky do sebe můžeme vnořovat. Větve ElseIf a Else jsou nepovinné. U dlouhé verze podmínky musí být za slovem Then konec řádku (jinak by se jednalo o zkrácenou podmínku) a povinný je samozřejmě i řádek End If.

Kód v jazyce C#
            if (podmínka)
                blok_příkazů
            else if (podmínka)
                blok_příkazů
            else if (podmínka)
                blok_příkazů
            else 
                blok_příkazů

Na místech podmínka se očekává výraz (musí být uzavřen v kulaté závorce), na místech blok_příkazů se očekává buď jeden příkaz, nebo blok více příkazů uzavřený do složených závorek {}. Konce řádků nejsou v C# signifikantní, takže můžete celou podmínku dát na jeden řádek, ovšem nedoporučuje se to, není to příliš přehledné.

Větve else if a else jsou nepovinné, na rozdíl od VB.NET, kde je speciální klíčové slovo ElseIf, je zde stejného významu docíleno vlastně vnořenými podmínkami. Celý kód by se dal naformátovat i takto, ovšem v praxi se to nepoužívá. Za prvním klíčovým slovem else je jeden příkaz, a to podmínka. Protože celá podmínka počínaje druhým slovem if v ukázce je jeden jediný příkaz, není nutné jej ohraničovat do složených závorek.

            if (podmínka)
                blok_příkazů
            else 
                if (podmínka)
                    blok_příkazů
                else 
                    if (podmínka)
                        blok_příkazů
                    else 
                        blok_příkazů

Větví ElseIf resp. else if může být libovolný počet, nemusí být samozřejmě ani jedna. Podmíněný výraz se vyhodnocuje tak, že se vyhodnocují popořadě výrazy na místech podmínka a první, který platí, se provede. Pokud tedy platí první podmínka, provede se první blok příkazů a další podmínky se netestují, tím pádem se další bloky příkazů nespustí. Pokud neplatí ani jedna podmínka a je uvedena větev else, provede se ta. Na místě podmínka může být výraz, o kterých je následující kapitolka.

Výrazy a operátory

Aritmetické operátory
VB.NET C# Popis
X + Y X + Y sčítání
X - Y X - Y odčítání
X * Y X * Y násobení
X / Y X / Y (X nebo Y desetinné číslo) dělení (desetinné)
X \ Y X / Y (X i Y celočíselné typy) celočíselné dělení
54 děleno 7 je 7
X Mod Y % zbytek po celočíselném dělení (modulo)
54 modulo 7 je 5
  X++ přičtení jedničky po vyhodnocení
  X-- odečtení jedničky po vyhodnocení
  ++X přičtení jedničky před vyhodnocením
  --X odečtení jedničky před vyhodnocením
X ^ Y   umocnění
X << Y X << Y bitový posun o Y bitů vlevo
X >> Y X >> Y bitový posun o Y bitů vpravo

Všechny operátory (kromě X++, ++X, X--, --X a Mod) mají i své varianty s přidaným znakem = na konec, které výsledek operace přiřadí pro prvního operandu. Např. X += Y sečte hodnotu Y do X a přiřadí výsledek do X, podobně X *= Y vynásobí vynásobí hodnotu X hodnotou Y a uloží ji do X.

Operátory X++, ++X, X-- a --X, které jsou dostupné jen v jazyce C#, fungují tak, že zvýší či sníží hodnotu proměnné o 1. Pokud jsou použity před proměnnou, nejprve se hodnota proměnné zvýší resp. sníží a pak až se použije. Pokud naopak použijeme tyto operátory za proměnnou, hodnota proměnné se nejprve použije ve výrazu a pak až se zvýší resp. sníží.

Pokud tedy v A je hodnota 3 a napíšeme X = ++A, pak se nejprve hodnota A nastaví na 4 a do X se pak přiřadí hodnota 4. Pokud ale v A je hodnota 3 a napíšeme X = A++, do X se nejprve nastaví hodnota A (tedy 3) a pak až se A zvýší o jedničku (takže v něm bude 4).

Operátory bitového posunu se chovají různě na datových typech se znaménkem a bez znaménka. U typů bez znaménka (UInt16, UInt32, Byte atd.) se nové pozice nalevo doplní nulami (tím pádem posun vlevo o 1 funguje jako násobení dvěma a posun o 1 vpravo funguje jako celočíselné dělení dvěma), u typů se znaménkem (Int32, SByte atd.) se nové pozice nalevo doplní hodnotou původního prvního bitu (takže se při posunech zachovává znaménko, což je první bit). Pokud vás zajímají detaily, podívejte se na článek na Wikipedii o aritmetickém a logickém posunu.

Relační operátory
VB.NET C# Popis
X < Y X < Y je menší
X <= Y X <= Y je menší nebo rovno
X > Y X > Y je větší
X >= Y X >= Y je větší nebo rovno
X <> Y X != Y není rovno
X = Y X == Y je rovno

Výsledkem výrazů s relačními operátory je hodnota typu System.Boolean.

Ve VB.NET je porovnávací operátor stejný jako operátor přiřazení. To, jestli se jedná o přiřazení či porovnání, se pozná podle kontextu. Ve VB.NET nelze ve výrazech operátor přiřazení použít, pokud je ve výrazu nalezen operátor =, jedná se vždy o porovnávání. Operátor přiřazení nevrací na rozdíl od C# žádnou hodnotu.

V C# je operátorem přiřazení znak =, kdežto porovnání je operátor ==. Operátor přiřazení navíc vrací hodnotu, pokud ve výrazu použijeme X = Y, vrátí se přiřazovaná hodnota. Toho můžeme využít například zde:

Kód v jazyce C#
    int i;
    if ((i = b * 7) == 0) ...

V podmínce nejprve přiřadíme do proměnné i výraz b * 7 a pak otestujeme, zda-li je jeho hodnota rovna nule. Pokud ano, provedou se příkazy podmínky. Zároveň ale v proměnné i už máme uložen výsledek tohoto výraz. Ve VB.NET je nutné toto přiřazení udělat nad podmínku, za slovem If může být pouze výraz a operátor = do výrazu nepatří.

Logické operátory
VB.NET C# Popis
X And Y X & Y bitový AND
X Or Y X | Y bitový OR
X Xor Y X ^ Y bitový XOR (platí buď X nebo Y, ale ne obě zároveň)
Not X !X negace
X AndAlso Y X && Y AND (pokud X neplatí, Y se vůbec netestuje)
X OrElse Y X || Y OR (pokud X platí, Y se vůbec netestuje)

První tři operátory se používají především pro bitové operace - fungují nad číselnými typy. Poslední 3 operátory se používají především v podmínkách - poslední dva dělají takzvané zkrácené vyhodnocování, čehož lze velmi dobře využívat.

Zkrácený AND nevyhodnocuje Y, pokud X neplatí a tím pádem i kdyby Y platilo, výsledek by byl stejně False. Obdobně zkrácený OR nevyhodnocuje Y, pokud X platí, protože i kdyby Y neplatilo, výsledek by byl stejně True.

Poznámka: Priority operátorů jsou popsány na těchto stránkách:

Literály čísel a znaků

Pokud někde v kódu uvedeme celé číslo (např. 15), existuje několik pravidel pro určení datového typu této hodnoty. Bere se to jako hodnota typu System.Int32, pokud se do tohoto rozsahu nevejde, bere se jako System.Int64, případně jako System.UInt64. Pokud uvedeme desetinné číslo (např. 15.0), bere se automaticky jako Double.

Pokud chceme ručně říci, jakého typu má číselná konstanta být, uvedeme za číslo příponu identifikující typ. V tabulce jsou uvedeny příklady použití:

VB.NET C# Datový typ
15F 15f System.Single
15R 15d System.Double
15US   System.UInt16
15UI 15u System.UInt32
15UL 15ul System.UInt64
15S   System.Int16
15I   System.Int32
15L 15L System.Int64
15D 15m System.Decimal
“a”C ‘a’ System.Char

Na velikosti písmen u přípon nezáleží, ale L se v C# kvůli přehlednosti píše velké (aby se nepletlo s jedničkou, kompilátor dokonce vyhodí varování), ostatní většinou velkými písmeny. Pro některé typy C# přípony nemá.

Pokud chcete zapsat literál typu System.Char v C#, stačí jej uzavřít jej do apostrofů (pro řetězce se používají uvozovky). Ve VB.NET se jednotlivé znaky zapisují do uvozovek s příponou C.

Výsledky výrazů a konverze typů

Pro konverzi číselných typů mezi sebou lze použít funkci či operátor přetypování. Ve VB.NET k tomuto účelu slouží funkce CInt, CLong, CShort, CByte, CUInt, CULong, CUShort, CSByte, CSng (na typ Single) a CDbl (na typ Double). V C# stačí před přetypovávaný výraz připsat do kulatých závorek název cílového datového typu, je to tzv. operátor přetypování.

Kód v jazyce Visual Basic .NET
Dim i As Integer = CInt(15.786)
Kód v jazyce C#
int c = (int)15.768;

Co se týče operátorů jako sčítání, odčítání atd., výsledným datovým typem výrazu bývá přesnější ze vstupních datových typů, minimálně ovšem 32bitový. Pokud tedy sčítáme typy Double a Single, výsledkem je Double. Pokud sčítáme dva Int32, výsledkem je Int32. Pokud ale sčítáme dva Byte, výsledkem je Int32 (výsledek je minimálně 32bitový datový typ, procesory s těmito typy pracují rychleji).

V C# tedy nelze napsat byte i = a + b, kde proměnné a a b jsou typu byte, musíme použít přetypování byte i = (byte)(a + b). Ve VB.NET to napsat jde i bez přetypování, protože standardně jsou povoleny tzv. narrowing conversions, což je automatická konverze číselného datového typu na typ s menším rozsahem nebo přesností. Ve VB.NET tedy klidně můžeme přiřadit Integer do Byte či Double do Single, v C# musíme přetypovávat. Pokud převedeme z Double na Single, ztratíme přesnost, pokud přiřadíme z Integer do Byte, ztratíme tím hodnoty vyšších bitů. Opačné konverze (widening conversions) na typ s větším rozsahem nebo přesností jdou v C# i bez přetypování, ve VB.NET pochopitelně také.

Řetězcové literály

Textové řetězce jsou v .NET Frameworku reprezentovány datovým typem (třídou) System.String. Pokud chceme zapsat řetězec jako literál v kódu, uzavřeme jej do uvozovek. Detaily se liší ve VB.NET a v C#.

Ve VB.NET je situace velmi jednoduchá - text ohraničený uvozovkami je brán jako řetězec. Pokud dovnitř řetězce chceme vložit uvozovky, zdvojíme je “”.

Kód v jazyce Visual Basic .NET
            Dim s1 As String = "Hello world!"       'Hello world!
            Dim s2 As String = "Hello ""fantastic"" world!"     'Hello "fantastic" world!

V C# máme situaci o trochu složitější, ale díky tomu máme více možností. Uvnitř řetězců můžeme používat tzv. escape sekvence. Pokud dovnitř řetězce dáme zpětné lomítko, následující znak bude mít speciální význam:

Sekvence Význam
\' Apostrof
\" Uvozovky
\\ Zpětné lomítko
\0 ASCII znak 0
\a Znak alert
\b Znak backspace
\f Znak form feed
\n Znak new line
\r Znak carriage return
\t Tabulátor
\v Vertikální tabulátor

Pokud tedy dovnitř řetězce umístíme někam sekvenci \t, místo ní se ve skutečnosti použije znak tabulátor. Pokud chceme do textu vypsat zpětné lomítko, zdvojíme jej atd.

Někdy se nám toto chování nehodí, protože řetězec obsahuje zpětných lomítek mnoho a bylo by to nepřehledné. Před první uvozovky, které zahajují řetězec, můžeme napsat zavináč. Díky tomu se budou escape sekvence uvnitř řetězce ignorovat a uvnitř řetězce mohou být jakékoliv znaky kromě uvozovek. Pokud chceme napsat uvozovky dovnitř takového řetězce, opět je zdvojíme. Řetězec, před kterým je zavináč, však může obsahovat konec řádku, jak ukazuje poslední ukázka.

Tuto ukázku jsem si vypůjčil ze specifikace jazyka C#.

Kód v jazyce C#
string a = "hello, world";                        // hello, world
string b = @"hello, world";                    // hello, world
string c = "hello \t world";                    // hello     world
string d = @"hello \t world";                    // hello \t world
string e = "Joe said \"Hello\" to me";        // Joe said "Hello" to me
string f = @"Joe said ""Hello"" to me";    // Joe said "Hello" to me
string g = "\\\\server\\share\\file.txt";    // \\server\share\file.txt
string h = @"\\server\share\file.txt";        // \\server\share\file.txt
string i = "one\r\ntwo\r\nthree";
string j = @"one
two
three";

Operátor pro slučování řetězců je ve VB.NET &, v C# +. Operátor + funguje i ve VB.NET.

For cyklus

Syntaxe cyklů je ve VB.NET téměř stejná jako v předchozích verzích VB, v C# je zase stejná jako v ostatních jazycích z céčkové rodiny.

Kód v jazyce Visual Basic .NET
For i As Integer = 0 To 14 Step 1
    blok_příkazů
Next

Ve VB.NET musí být iterační proměnná cyklu nějakého číselného typu. Pokud proměnnou nemáme deklarovanou před cyklem a chceme ji používat pouze uvnitř cyklu a ne už za ním, můžeme za jejím názvem uvést As Integer, čímž proměnnou i nadeklarujeme pouze v rámci daného cyklu. Za rovnítko uvedeme počáteční hodnotu, za slovo To cílovou hodnotu a volitelně můžeme přidat Step krok, kde krok je hodnota, která se přičte k iterační proměnné i po ukončení každého průchodu těla cyklu. Pokud krok neuvedeme, použije se výchozí hodnota, tedy 1.

Tělo cyklu se bude provádět, dokud je i menší nebo rovno koncové hodnotě při kladném kroku, anebo dokud je i větší nebo rovno koncové hodnotě při záporném kroku. Na místě blok_příkazů může být jeden nebo více příkazů.

Kód v jazyce C#
for (int i = 0; i < 15; i++)
    blok_příkazů

V C# máme možnosti o dost širší. V závorce v první části před středníkem může být libovolný příkaz, který se spustí před zahájením prvního průchodu cyklu. Pokud je v něm deklarace proměnné (což nejčastěji bývá), platí proměnná jen v rámci tohoto cyklu. Může tam být ale jakýkoliv příkaz.

Ve druhé části je podmínka, která se před každým průchodem vyhodnotí a pokud neplatí, provádění cyklu skončí. Poslední část je příkaz, který se spustí po každém průchodu (opět nemusíme inkrementovat zrovna i, můžeme dělat cokoliv jiného).

Přestože máme v C# obrovskou volnost v tom, co budeme s for cyklem dělat, důrazně vás varuji před vymýšlením krkolomných cestiček, jak veškerou logiku cyklu nacpat do hlavičky cyklu a nemuset psát tělo. Takové cykly se velmi špatně luští a činí kód nepřehledným. V drtivé většině případů doporučuji používat standardní syntaxi, která je konec konců uvedena i v příkladu - v první části deklarace a inicializace, ve druhé části jednoduchá podmínka, ve třetí inkrementace o zvolený krok. Každému je hned jasné, co cyklus dělá.

Na místě blok_příkazů může být jeden příkaz nebo blok příkazů ohraničený složenými závorkami.

Poznámka: Je zde ještě jeden drobný detail. Pokud ve VB.NET za klíčové slovo To uvedete výraz, vyhodnotí se pouze jednou, a to před spuštěním cyklu, a dále ne. Pokud se jeho hodnota změní během provádění cyklu, nic se neděje a cyklus jede dál. Například pokud budete mít nějakou sadu položek, jejichž počet je třeba v proměnné n, uděláte cyklus od 0 do n - 1 a v některém kroku určité položky smažete, čímž se změní počet, tak přestože proměnná n bude mít hodnotu třeba 23, cyklus klidně poběží do 25, protože hodnota se určila na začátku platí ta. Je třeba použít jiný druh cyklu. V C# tohle už z principu není možné, podmínka se vyhodnocuje vždy, protože může být jakákoliv a vůbec nemusí jít o nějaké porovnávání, může to být třeba volání nějaké funkce.

While cyklus

Cykly while jsou co do funkčnosti v obou jazycích ekvivalentní. Mají následující strukturu:

Kód v jazyce Visual Basic .NET
While podmínka
    blok_příkazů
End While
Kód v jazyce C#
while (podmínka)
    blok_příkazů

Na místě podmínka je výraz vracející typ Boolean. Na místě blok_příkazů může být ve VB.NET jeden nebo více příkazů oddělených koncem řádku nebo dvojtečkou, v C# pak buď jeden příkaz, nebo blok příkazů ohraničený složenými závorkami.

Nejprve se vyhodnotí podmínka, pokud platí, provede se tělo cyklu, a tento postup se opakuje. Jakmile podmínka přestane platit (což může být klidně i při prvním otestováním), provádění cyklu končí. Tělo cyklu se tedy nemusí spustit ani jednou.

Do cyklus

Posledním typem cyklů je cyklus do. Ten má ve VB.NET více možností, ovšem většinou se používá jen tak, která je k dispozici v C#, ostatní jsou nahraditelné.

Kód v jazyce Visual Basic .NET
Do
    blok_příkazů
Loop While podmínka

Místo klíčového slova While můžeme ve VB.NET použít ještě klíčové slovo Until, přičemž sekce While/Until podmínka může být i za klíčovým slovem Do (dvě podmínky mít cyklus ale nesmí, povolena je jen jedna).

Pokud je specifikováno While, tělo cyklu se opakuje, pokud podmínka platí. Pokud je specifikováno Until, tělo cyklu se opakuje, pokud podmínka neplatí. To, jestli je podmínka uvedena za Do nebo za Loop, určuje, kdy se bude podmínka testovat. Pokud je uvedena za Do, otestuje se před prvním průchodem těla cyklu. Pokud je až za Loop, testuje se až po prvním průchodu. Cyklus Do While … Loop je ekvivalentní předchozímu typu cyklu While, ostatní varianty dělají něco nepatrně jiného. Rozdíl mezi While a Until je jen v negaci podmínky.

do
    blok_příkazů
while (podmínka)

V C# je povolena pouze tato konstrukce, která spolu s while cyklem pokrývá všechny případy, které jsou v běžné praxi potřeba.

Navigace v cyklech

Uvnitř cyklů můžeme používat klíčová slova Exit resp. break a continue. Použitím slova Exit / break okamžitě ukončíme provádění daného cyklu. Použitím slova continue přestaneme provádět daný krok a ihned pokračujeme dalším (před tím se otestuje samozřejmě podmínka). Tyto konstrukce můžeme použít v cyklech For, While a Do.

Kód v jazyce Visual Basic .NET
For i As Integer = 0 To 9
    If i = 3 Then Continue For
    If i = 5 Then Exit For
Next
Kód v jazyce C#
for (int i = 0; i < 10; i++)
{
    if (i == 3) continue;
    if (i == 5) break;
}

Pokud máme v sobě více vnořených cyklů, dané break a continue se vztahuje na hierarchicky nejbližší cyklus. Ve VB.NET můžeme pomocí klíčového slova za Exit resp. Continue určit typ cyklu, takže pokud budeme mít For cyklus uvnitř While cyklu, voláním Exit While vyskočíme z vnějšího While cyklu. Pokud máme dva stejné typy cyklů v sobě, platí vždy ten hierarchicky nejbližší, tzn. ten vnitřní.

Rozhodovací struktury

Oba dva jazyky podporují i tzv. rozhodovací struktury. Syntaxe i možnosti se poměrně liší, ale v zásadě umí to samé.

Kód v jazyce Visual Basic .NET
Select Case výraz
    Case 15
        blok_příkazů
    Case Is >= 17
        blok_příkazů
    Case Else
        blok_příkazů
End Select

Hodnota na místě výraz se porovná s hodnotami uvedenými za Case a spustí se první větev, která vyhovuje výsledku. Pokud nevyhovuje žádná větev a existuje větev Case Else (je nepovinná), provede se ta. Za slovem Case může být buď přímo hodnota, nebo podmínka tvaru Is operátor hodnota. To v C# nejde.

Kód v jazyce C#
switch (výraz)
{
    case 15:
    case 16:
        blok_příkazů;
        break;
    case 17:
        blok_příkazů;
        goto case 18;
    case 18:
        blok_příkazů;
        break;
    default:
        blok_příkazů;
        break;
}

V C# to funguje velmi podobně, ale s několika drobnými rozdíly. Za blokem příkazů v každé větvi musí být buď klíčové slovo break, které ukončí provádění struktury, anebo klauzule goto case hodnota, která skočí na danou větev. Jedna z těchto věcí tam ale být musí, není možné “propadnout” se do nižší větve jako v C/C++.

Větev může být i prázdná, v tom případě pokud výraz vyhovuje hodnotě takové větve, použije se větev následující. Pokud je tedy hodnota výrazu v ukázce 15 nebo 16, použije se první blok příkazů. Pokud je rovna 17, provede se druhý blok příkazů a pak ještě třetí blok, na který jsme skočili použitím goto case. Za case nemůže být podmínka, jen konstanty.

Větev default je samozřejmě nepovinná a provede se, pokud neplatila žádná testovaná podmínka. Na místech blok_příkazů je jeden nebo více příkazů (nemusí se uzavírat do složených závorek).

Platnost proměnných

Deklarace proměnných můžeme mít v kódu prakticky kdekoliv, musí to být uvnitř nějakého typu (třídy nebo struktury). Pokud je to přímo v těle třídy či struktury, platí tato proměnná v rámci dané třídy / struktury. Pokud proměnnou nadeklarujeme v metodě, platí pouze v dané metodě. Pokud ji nadeklarujeme v hlavičce for cyklu, platí jen v tom for cyklu (hodnota se zachová přes všechny průchody cyklem). Pokud ji nadeklarujeme uvnitř těla cyklu, bude proměnná platit jen v těle cyklu a na konci každého průchodu cyklem se zruší.

Kód v jazyce Visual Basic .NET
Private Function Funkce(ByVal i1 As Integer) As Integer
    Dim i2 As Integer
    If i1 = 5 Then
        Dim i3 As Integer
        For i4 As Integer = 0 To 9
            Dim i5 As Integer
        Next
    End If
End Function

Kód v jazyce C#

int Funkce(int i1)
{
    int i2;
    if (i1 == 5)
    {
        int i3;
        for (int i4 = 0; i4 < 10; i4++)
        {
            int i5;
            
        }
    }
}

Kde mají platnost proměnné i1i5?

  • Proměnná i1 je argumentem metody Funkce, je tedy dostupná v rámci onoho volání metody. Každé volání metody Funkce má svoji proměnnou i1.
  • Proměnná i2 je deklarována uvnitř funkce a je na tom stejně jako argument metody.
  • Proměnná i3 je deklarována uvnitř větve podmínky, platí tedy v konkrétní větvi podmínky. Pokud bychom přidali větev else, v ní již proměnná platit nebude.
  • Proměnná i4 je deklarována v hlavičce for cyklu. Má platnost po celou dobu trvání cyklu.
  • Proměnná i5 je deklarována uvnitř těla cyklu, má platnost po dobu trvání jednoho kroku cyklu.

Proměnná i0, kterou v ukázce nemáme a která by byla deklarována na stejné úrovni jako metoda, tedy uvnitř třídy nebo struktury, by byla sdílená pro všechna volání metody Funkce.

Závěrem

V tomto díle jsme si ukázali základní elementy jazyků VB.NET a C#. Příště si budeme povídat podrobněji o datových typech, třídách a dalších věcech, které jsou pro pořádné programování nezbytné.

 

hodnocení článku

1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

7. Rozhraní 19.07.2010
6. Dědičnost - dokončení 01.01.2010
5. Dědičnost 09.09.2009
4. Třídy 09.06.2009
3. Datové typy 05.05.2009
2. Základní elementy VB.NET a C# 18.04.2009
1. Úvod do .NET Frameworku 03.04.2009

 

 

 

Nový příspěvek

 

Označování bitů

Zdravím, měl bych připomínku u bitového posunu. Totiž uvádíte, že znaménko je uchováno v 1. bitu. Číslování se však běžně uvádí již od tzv. 0. bitu nebo též označovaného jako nejméně významný bit (LSB). Dle velikosti datového typu potom nejvíce významný bit (MSB) může odpovídat 7. bitu pro Byte, 15. bit pro short atd. Právě v posledně zmiňovaném bitu u znaménkových datových typů je informace o znaménku uchována. To je jaksi v rozporu s tvrzením zde uváděným a minimálně může působit zmatečně - tedy ještě jsem se nesetkal se zdrojem který by uváděl číslování bitů zleva doprava pokud to tímto způsobem bylo zamýšleno.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Základní elementy VB.NET a C#

pretypovani v C# timto stylem

int c = (int)15.768;

je velmi nesikovne a ve Vistach a W7ckach 64bit se muzou vyskytnout nehodne pady programu. Proto by se melo vyuzivat classy Convert

int c = Convert.ToInt16(15.768);

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Mohl byste uvést zdroj této informace? Podle mě je to totiž naprostý nesmysl, int (tedy System.Int32) je v C# vždy a všude 32bitový integer a 15.768 se vždy reprezentuje jako System.Double, které je definováno normou IEEE a je nezávislé na platformě (řeší se akorát big a little endian, ale to je něco jiného). To, jestli jde o 32 bitovou nebo 64 bitovou platformu nehraje žádnou roli.

Docela by mě zajímalo, kde jste na takovou informaci přišel - .NET má totiž obecně jako jednu z hlavních zásad, že jeho aritmetika nezávisí na platformě, kde jej provozujeme. Zkoušel jsem o tomhle hledat zmínku na Googlu, ovšem neúspěšně.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Základní elementy VB.NET a C#

Rád bych se zeptal ještě ohledně Namespace, moc tomu nerozumím. K čemu mi Namespace jsou? Pokud je použiji, tak jak? Mám jakoby obalit třídu?

Namespace MojeNamespace
  Public Class Class1
  ...
  End Class
End Namespace

Ve VS2008 mám např. Class1.vb a Class2.vb, čili fyzicky dva soubory. Pokud bych tyto třídy chtěl dát do jednoho namespace, tak je obě obalím stejným názvem Namespace? Nebo je dám do jednoho souboru?

Ještě se mi to míchá s pojmem assembly. Platí, že jedna assembly může mít více namespace nebo obráceně?

A jaký je rozdím mezi References a Imported namespaces?

Děkuji.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Namespace je čistě a jen k "vytváření skupin tříd s podobnou funkcí", využívá se také k možnosti mít stejné názvy různých tříd (třeba autor knihovny pro stahování mailů asi bude mít třídu MailDownloader, a takových knihoven je mnoho, každá si vymyslí svůj vlastní namespace).

Pokud třídu ohraničíte blokem Namespace (uvniř bloku může být víc tříd, nebo i jiné deklarace, např. struktury, výčtové typy apod.) , vše, co je v tomto bloku se zařadí do daného namespace. Pokud chcete mít každou třídu v separátním souboru (což vřele doporučuji), pak třídy prostě vždy ohraničte blokem namespace se stejným názvem a je to.

V jedné assembly může být namespaces libovolný počet, to jsou prostě jen názvy, samy o sobě nemají žádnou funkci.

Importování namespace znamená, že celé názvy tříd včetně jejich namespaců nemusíte vypisovat a prostě napíšete jen název třídy. References je seznam assembly, které obsahují datové typy, které budeme v naší assembly potřebovat. Pokud používáte třeba třídu System.Drawing.Image, musíte mít referencovanou assembly System.Drawing, aby se tato knihovna v případě potřeby mohla načíst do paměti.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

A co znamená assembly a namespace uvedená ve vlastnostech projektu? Mám ji pak ještě uvádět u jednotlivých tříd?

Souvisí assembly nějak s tím kolik dll se mi z mého solution vyrobí? Pokud mám v solution 3 projekty, bude každý projekt jedno dll nebo nemusí?

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Základní elementy VB.NET a C#

Moc hezky vysvětleno...

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback