4. Zabalení (boxing)
• Pokud je na místě, kde se očekává instance referenčního typu,
potřeba použít hodnotový typ (typicky předdefinované kolekce
System.Collection), je potřeba zařídit převod.
• C# nabízí pro převod instance hodnotového typu na referenční typ
operaci zabalení (boxing). Pro opačný převod pak vybalení
(unboxing).
5. Zabalení (boxing)
Pokud se přiřadí odkazu na typ object hodnota hodnotového typu,
object o = 11;
vytvoří překladač instanci „obalové“ třídy, do které uloží hodnotu z
pravé strany. Tuto hodnotu lze získat kdykoli zpět přetypováním
int i = (int)o;
• Za běhu programu se kontroluje, zda má přetypování smysl. Jinak se
vyvolává výjimka System.InvalidCastException
6. Příkazy
• Hlavní rozdíly mezi C++ a C#
V C# není příkaz asm.
Trochu odlišná pravidla platí pro switch a goto.
V C# má výrazový příkaz silnější pravidla.
V C# jsou příkazy navíc
foreach, checked, unchecked, lock, using a yield.
7. Příkazy – základní konstrukce
• Výrazový příkaz
Vzniká připojením středníku na konec výrazu.
Syntaxe
výraz ;
Na rozdíl od C++ nelze použít libovolný výraz, ale pouze výraz, který má
vedlejší efekt.
A+B;
5;
Operátory ++, --,
přiřazení, volání metody,
…
8. Příkazy – základní konstrukce
• Blok
Všude tam, kde lze použít příkaz, lze použít i složený příkaz – blok.
Syntaxe
{ příkazynep }
Libivolné příkazy včetně deklarací a
vnořených bloků.
9. Příkazy – základní konstrukce
• Blok
Na rozdíl od C++ nelze ve vnořeném bloku deklarovat stejný identifikátor
jako ve vnějším.
{ // Začátek vnějšího bloku
int i = 5;
{ // Začátek vnitřního bloku
int i = 6;
}
}
V C# chyba.
10. Příkazy – základní konstrukce
• Deklarace
Plnohodnotný příkaz – může se objevit kdekoli mezi ostatními příkazy.
11. Rozhodování
• if
Způsob použití je stejný jako v C++
Syntaxe
if (podmínka) příkaz1
if (podmínka) příkaz1 else příkaz2
podmínka – výraz typu bool nebo typu, který lze
implicitně zkonvertovat na typ bool nebo na typ,
který má operator true().
Na rozdíl od C++ zde nelze deklarovat proměnnou
nebo použít čísla a reference.
13. Rozhodování
• switch
Odlišnosti oproti C++
Jako konstanty v návěstích case lze použít i znakové řetězce a jako řídící výraz
lze použít proměnnou typu string.
Program nesmí přejít automaticky z jedné alternativy do druhé – každá
alternativa musí být ukončena break, goto, return nebo throw.
Program může přejít do jiné alternativy jen pomocí příkazu goto s uvedením
návěstí.
14. Rozhodování
• switch
Příklad: https://goo.gl/byJ9hf
string s; while (true)
{
Console.WriteLine("Zadej text");
s = Console.ReadLine();
switch (s)
{
case "while":
case "switch":
Console.WriteLine("Zadal jsi klíčové slovo");
break;
case "konec":
return;
case "if":
goto case "while";
case "":
15. Cykly
• V příkazu cyklu lze stejně jako v C++ používat příkazy break a
continue.
• while
Syntaxe
while(podmínka) příkaz
Odlišnosti oproti C++ jsou v podmínce – totéž
jako u příkazu if
16. Cykly
• for
Syntaxe
for ( incializacenep ; podmínkanep ; kroknep ) příkaz
Zde lze
deklarovat
proměnné. Lze
uvést několik
výrazů
oddělených
čárkou.
Platí totéž co
pro podmínku
příkazu if.
Jeden nebo
skupina příkazů
oddělených
čárkou.
18. Cykly
• foreach
Slouží k iteraci všech prvků v kolekci (kontejneru)
Syntaxe
foreach(typ identifikátoru in výraz) příkaz
Musí určovat
nějakou kolekci
Řídící proměnná
cyklu. Deklarace
proměnné, do které
se ukládají
jednotlivé hodnoty
prvků z kolekce
19. Cykly
• foreach
Jako kolekci lze použít jakýkoli datový typ implementující rozhraní
IEnumerable nebo jeho generickou obdobu, tedy typ obsahující veřejnou
metodu GetEnumerator().
Jako kolekci lze též použít metodu či vlastnost obsahující iterátor.
Vrací hodnotu E, kterou lze
použít jako enumerátor.
20. Cykly
• foreach
E implementuje Ienumerator, obsahuje tedy:
bool MoveNext()
Reset()
Current
Přejde na další prvek kolekce. Vrací false, pokud
už další prvek v kolekci neexistuje.
Veřejná metoda. Nastaví enumerátor do výchozí
pozice (před první prvek).
Vlastnost poskytující aktuální prvek kolekce.
21. Cykly
• foreach
Enumerátor může být jak referenčního, tak hodnotového typu.
Průběh
• Vyhodnotí se výraz, tím se získá kolekce K. Má-li výraz
hodnotu null, vyvolá se výjimka
Syste.NullReferenceException.
• Pomocí K.GetEnumerator() se získá enumerátor E. Pokud
je E referenčního typu a má hodnotu null, vyvolá se výjimka
Syste.NullReferenceException
• Provádění cyklu skončí, když E.MoveNext() vrací false.
22. Skoky
• jump statements – způsobují přenos řízení
• break, continue, goto, return a throw
Stejný
jako v
C++
Stejný
jako v
C++
Stejný
jako v
C++
23. Skoky
• goto
Syntaxe
goto identifikátor ;
goto default ;
goto case konstanta ;
Stejný jako v C++
Pouze v těle příkazu switch.
Pouze v těle příkazu switch.
24. Skoky
• Throw
Význam stejný jako v C++
Slouží k vyvolání výjimky
Syntaxe
throw výraz ;
Odkaz na instanci třídy odvozené od
System.Exception. Pokud je null, vyvolá
se System.NullReferenceException
25. Příkaz using
• V C++ neexistuje
• Řídí životnost objektů, které zpravidla spravují resources (např.
soubory)
• Syntaxe
using (získání_prostředku) příkaz;
deklarace_lokální_proměnné
výraz
26. Příkaz using
• Prostředek – instance třídy nebo struktury, která
implementuje rozhraní System.IDisposable, které obsahuje
metodu void Dispose().
• Deklarace lokální proměnné – deklarace proměnné s
inicializací, která představuje prostředek.
• Výraz – výraz, jehož výsledkem je prostředek.
• Příkaz – příkaz, v němž se nesmí přiřadit jiná hodnota do
proměnné deklarované v části získání prostředků.
27. Příkaz using
• Příklad ekvivalentních konstrukcí
using (R r = new R()) {
r.f();
}
R r = new R();
try {
r.f();
}
finally {
if (r != null) ((IDisposable)r).Dispose();
}
28. Příkaz using
• Je možné deklarovat i několik proměnných stejného typu
oddělených čárkou.
using (R r1 = new R(), r2 = new R()) {
r1.f();
r2.f();
}
using (R r1 = new R()) {
using (R r2 = new R()) {
r1.f();
r2.f();
}
}
29. Příkaz lock
• Nemá v C++ obdobu.
• Slouží k synchronizaci mezi podprocesy (threads) programu
pomocí vzájemně výlučných zámků – mutexů.
• Syntaxe
lock (výraz) příkaz
• Příkaz lock získá pro daný objekt mutex, vyvolá příkaz a
mutex uvolní.
Odkaz na referenční typ. Zde
nedochází k zabalení
hodnotových typů.
30. Příkaz lock
lock (x) {
/* ... */
}
object obj = x;
System.Threading.Monitor.Enter(obj);
try {
/* ... */
}
finally {
System.Threading.Monitor.Exit(obj);
}
Přiřazení výrazu x do proměnné
obj je zde proto, aby se výraz x
vyhodnotil pouze jednou.
31. Příkaz lock
• Pro statické metody třídy se často jako zámek používá
instance třídy Type – získá se prostřednictvím operátoru
typeof.
• Pro vyloučení současného volání přidej a odeber lze psát:
class SynchronizovanýObjekt
{
public static void Přidej(object x)
{
lock(typeof(SynchronizovanýObjekt)) { /* tělo metody */ }
}
public static void Odeber(object x)
{
lock(typeof(SynchronizovanýObjekt)) { /* tělo metody */ }
}
}
32. Příkaz yield
• V C++ neexistuje
• Používá se v iterátoru – viz dále.
33. Příkaz try
• Podobně jako v C++ se jedná o pokusný blok
Zachycení a ošetření výjimek – viz výjimky
34. Operátory a výrazy
• Přehled operátorů
Operátory se ve výrazu vyhodnocují na základě priority. Nejdříve se
vyhodnocují operátory s vyšší prioritou. Pokud má více operátorů
stejnou prioritu, vyhodnocují se podle jejich asociativity.
Prioritu lze měnit pomocí kulatých závorek, ty mají nejvyšší
prioritu.
• Binární operátory jsou asociativní zleva doprava.
• Unární, přiřazovací, ternární a operátor nulového
sjednocení jsou asociativní zprava doleva.
35. Operátory a výrazy
• Přehled operátorů
http://msdn.microsoft.com/en-us/library/6a71f45d.aspx
36. Operátory
• Poznámky:
V C# se za operátor považují i () za účelem změny pořadí vyhodnocování.
V C++ jsou považovány za oddělovač.
V C# je operátor new operátorem volání konstruktoru. V C++ je
alokátorem.
Praktický
význam pro
programátora?
žádný!
V C# se alokace
sturktur
neprovádí.
37. Operátory
• Poznámky:
V C# chybí oproti C++ některé operátory přetypování.
A také některé další operátory (např. pro třídní ukazatel)
static_cast,
dynamic_cast,
reinterpret_cast a
const_cast
.*,
->*,
typeid
38. Operátory
• Poznámky:
V C# lze některé operátory využít pouze v nezabezpečeném kódu.
stackalloc (alokace na zásobníku)
sizeof (velikost hodnotového typu)
-> (přístup ke složce struktury)
* (dereferencování ukazatele)
& (získání adresy)
39. Číselná rozšíření
• Unární rozšíření
Implicitní konverze uplatňující se pro předdefinované unární operátory +,
- a ~
sbyte, byte, short, ushort a char se implicitně převádí na typ int
uint se při použití minus převádí na long
Bitový
doplněk
sbyte a = -1;
a = -a; //Chyba, na rozdíl od C++ nelze implicitně konvertovat int na sbyte
40. Číselná rozšíření
• Binární rozšíření
Implicitní konverze obou operandů na společný typ (ten nebo bool bude
také typem výsledku) při použití předdefinovaných binárních operátorů +,
-, *, /, %, &, |, ^, ==, !=, <, >, <=, >=.
Pravidla
1. Pokud je první z operandů decimal, převede se druhý též na decimal.
Chyba nastane, pokud je druhý operand typu float nebo double, protože
neexistuje implicitní konverze.
V případě relačních
operátorů.
41. Číselná rozšíření
• Binární rozšíření
Pravidla
2. Pokud je jeden operand double, druhý se převede na double.
3. Pokud je jeden operand typu float, druhý se převede na float.
4. Je-li jeden z operandů typu ulong, převede se druhý na ulong, pokud není
sbyte, short, int nebo long (jinak chyba).
5. Pokud je jeden z operandů typu long, převede se druhý na long.
42. Číselná rozšíření
• Binární rozšíření
Pravidla
6. Pokud je jeden z operandu uint a druhý je typu sbyte, short nebo int,
převedou se oba operandy na long.
7. Jinak, pokud je jeden z operandů typu uint, převede se druhý na uint.
8. Jinak se oba operandy převedou na int.
43. Některé operátory
• Operátor tečka
Specifikuje přístup ke statickým a nestatickým složkám tříd, struktur,
výčtových typů a jmenných prostorů. Nahrazuje ., -> a :: z C++
• Typeof
Zjišťování typu
Podobný význam jako typeid z C++
Typeof lze použít jen na jméno typu, nikoli na výraz. K tomu lze použít
metodu GetType().
if ((a + b).GetType() == typeof(int)) { /* ... */ }
44. Některé operátory
• is
Zjišťování typu
Syntaxe
výraz is typ
výraz – výraz referenčního typu
typ – jméno typu třídy, struktury či rozhraní
Vrací true pokud lze výraz přetypovat na typ.
Pro hodnotové typy lze operátor is použít, pokud je výraz typu object.
45. Některé operátory
• Přetypování
Na rozdíl od C++ se vždy kontroluje, zda má přetypování smysl.
(typ)
Stejně jako v C++.
Pokud je při kompilaci zjištěna nemožnost přetypování, ohlásí překladač chybu.
Pokud se tato nemožnost objeví až za běhu programu, dojde k vyvolání výjimky
System.InvalidCastException
as
K přetypování mezi referenčními typy.
Syntaxe
výraz as typ
46. Některé operátory
• Přetypování
as
Syntaxe
výraz as typ
výraz – reference na instanci, která se má přetypovat nebo hodnota, která se má
zabalit.
typ – cílový referenční typ
Je-li možné přetypování je výsledkem typ, jinak null.
static void Vypis(object r)
{
string s = r as string;
if (s != null) Console.WriteLine(s);
}
47. Některé operátory
• Bitové posuny
<< a >>
Levý operand musí být celočíselného typu. Sbyte, byte, short, ushort a char
se převádí na typ int.
Pravý operand musí být typu int nebo se na něj musí nechat implicitně
zkonvertovat.
Výsledkem je hodnota typu levého operandu.
48. Některé operátory
• Rovná se, nerovná se
== a !=
Lze použít i k porovnání zda reference ukazují na stejný objekt.
Např. u string přetíženo na porovnání obsahu.
Pokud v době překladu je známo, že reference ukazují na různé instance,
překladač ohlásí chybu.
Lze porovnávat instance delegátů. Jsou si rovny, jsou-li stejného typu a:
oba obsahují null, nebo
ukazují na tutéž statickou či nestatickou metodu a stejný objekt
Mohou ukazovat na více
stejných metod.
49. Některé operátory
• Podmíněný operátor
?:
Na rozdíl od C++ smí být první operand pouze bool, nebo typ, který lze
implicitně přetypovat na bool, nebo obsahuje operator true.
Typ výsledku výrazu A ? X : Y je určen podle:
Je-li typ X a typ Y stejný, bude tento i typem výsledku.
Existuje-li implicitní konverze z typu výrazu X na typ výrazu Y a neexistuje-
li implicitní konverze z Y na X, bude typem výsledku typ Y.
Existuje-li implicitní konverze z typu výrazu Y na typ výrazu X a neexistuje-
li implicitní konverze z typu X na typ Y, bude typem výsledku typ X.
Jinak nelze typ výsledku určit a překladač oznámí chybu.
50. Preprocesor
• V C# se hovoří o tzv. „direktivách preprocesoru“ – nezpracovává je
však preprocesor jako v C++, ale překladač.
• Podmíněné symboly
Neexistují makra
Symbol #define
Slouží k definování podmíněného symbolu
Syntaxe
#define identifikátor
51. Preprocesor
• Podmíněné symboly
Symbol #define
Musí být v programu před všemi ostatními direktivami preprocesoru (tedy i před
using).
Identifikátor je definován od #define do konce zdrojového souboru.
Definice podmíněného symbolu pro všechny překládané části sestavení: menu
Project > Properties, část Build, pole Conditional compilation symbols.
#define LADĚNÍ
using System;
// další příkazy programu
52. Preprocesor
• Podmíněné symboly
Symbol #undef
Slouží ke zrušení podmíněného symbolu zavedeného direktivou #define nebo ve
vlastnostech profilu
Musí být v programu před všemi ostatními direktivami, které nejsou direktivami
preprocesoru
53. Preprocesor
• Podmíněný překlad
Pomocí symbolu #if, podobně jako v C++
Schéma
#if podmíněný_výraz_1
zdrojový_text_1
#elif podmíněný_výraz_2
zdrojový_text_2
// ...
#else
zdrojový_text_n
#endif
#elif se může
opakovat
několikrát
#elif a #else lze
vynechat
55. Preprocesor
• Podmíněný překlad
Složitější podmíněné výrazy – mohou obsahovat ==, !=, &&, ||, konstanty
true a false.
Na rozdíl od C++ nemohou podmíněné výrazy obsahovat číselné konstanty
ani konstanty definované pomocí const.
#if LADĚNÍ == false
Console.WriteLine("x = " + x);
#endif
#if (LADĚNÍ || TESTOVÁNÍ)
Console.WriteLine("y = " + y);
#endif
56. Preprocesor
• Podmíněný překlad
Pokud je program v prostředí Visual Studio překládán v ladícím režimu (v
poli Solution Configuration je zvolena položka Debug), je automaticky
definován symbol DEBUG.
57. Preprocesor
• Chybová hlášení
Direktiva #error
Podobně jako v C++.
Způsobí výpis chybové zprávy a zastaví překlad.
Direktiva #warning
Způsobí výpis chybového hlášení, avšak nezastaví překlad.
Chybové hlášení -
zpráva bez uvozovek.
Případné uvozovky
jsou součástí
výstupu.
Obě direktivy lze
použít pouze ve
zdrojovém textu
direktivy #if.
58. Preprocesor
• Oblast zdrojového kódu
Direktivy #region a #endregion
Slouží k vymezení oblasti.
V C++ neexistují
Syntaxe
#region zprávanep
#endregion zprávanep
Visual Studio umožňuje takto
označené oblasti „skrýt“ (zabalit)
Nesmí se křížit, mohou se vnořovat
Nemění význam
programu. Jen
označují oblast ve
zdrojovém kódu.
59. Preprocesor
• Řádkování
Direktiva #line
Umožňuje při překladu změnit počítání řádků a název souboru.
Stejné jako v C++
Syntaxe
#line číslo název_souborunep
číslo – celé číslo, které má překladač považovat za aktuální číslo řádku.
název_souboru – jaké jméno souboru má překladač považovat za aktuální (bez
uvozovek)
60. Preprocesor
• Pragma
Direktiva #pragma
Ke specifikaci kontextových informací pro překladač
Význam může být v různých překladačích odlišný
Ve Visual Studio 2012:
#pragma warning – zapnutí či vypnutí určitého varování
#pragma checksum – generování kontrolního součtu zdrojového souboru
/// <summary>
/// Základní barvy.
/// </summary>
public enum Barva
{
#pragma warning disable 1591
červená, zelená, modrá
#pragma warning restore 1591
}
Číselný seznam
varování,
oddělených čárkou
61. TŘÍDY
• Rozdíly mezi C++ a C#
V C# není podporována vícenásobná (a tedy i virtuální) dědičnost
V C# lze dědičnost u tříd zakázat
Všechny třídy v C# mají společného předka – object
V C# lze vytvářet pouze dynamické instance, o jejich dealokaci se stará
automatická správa paměti.
Význam destruktoru je podstatně menší než v C++.
Třídy mohou implementovat rozhraní
Mohou obsahovat kromě datových složek, metod, konstruktorů a
destruktorů také vlastnosti, události, přetížené operátory a vnořené typy.
62. TŘÍDY
• Základní informace
Deklarace
modifikátorynep partialnep class identifikátor předeknep tělo;nep
modifikátory - přístupová práva, uvádí se pro každou složku zvlášť, mohou
dále obsahovat specifikaci abstract, sealed, new či static
identifikátor – jméno deklarované třídy
předek – předek třídy a implementovaná rozhraní
tělo - skupina deklarací ve složených závorkách; může však být i
prázdné
modifikátor partial – definice částečné třídy
Deklarace třídy nemůže být jako lokální typ (v metodě), ale jen v
prostoru jmen či v jiné třídě/struktuře (jako vnořený typ)
63. TŘÍDY
• Základní informace
Přístupová práva
Určují přístupnost složek v rámci třídy, v potomcích, v sestavení této třídy a v
ostatních sestaveních
stupeň třída sestavení potomci ostatní
public X X X X
protected internal X X X
protected X X
internal X X
private X
64. TŘÍDY
• Základní informace
Přístupová práva
private (soukromé složky) a protected (chráněné složky) – stejný význam
jako v C++
public (veřejné složky) – pokud má třída jako celek modifikátor public, je pak
daná složka veřejně přístupná všem sestavením.
internal (interní, vnitřní složky) – složka je přístupná všem součástem
sestavení, v němž je třída definována.
protected internal – sjednocení přístupového práva internal a
protected. Složka je přístupná jak ve tříde, v níž je deklarována, tak ve všech
potomcích bez ohledu na sestavení.
65. TŘÍDY
• Základní informace
Přístupová práva
Není-li specifikátor přístupových práv uveden, jedná se o složku soukromou
(private).
Datový typ složky nesmí mít širší přístupová práva než kterýkoli z dalších typů
uvedených v deklaraci.
Př.: potomek nesmí mít širší přístupová práva než předek.
Př.: metoda nesmí mít širší přístupová práva, než typ, který vrací.
class A {} // je internal
public class B {
public A f() { /* ... */ } // Chyba
}
internal
vs.
public
66. TŘÍDY
• Datové složky
Deklarace je podobná deklaraci proměnných.
Lze navíc použít atributy a modifikátory new a readonly.
Statické a nestatické.
67. TŘÍDY
• Datové složky
Nestatické datové složky
Instance fields
Složky jednotlivých instancí (stejně jako v C++)
Třída může obsahovat datovou složku svého vlastního typu:
public class Prvek
{
private Prvek další; // OK
// ...
}
odkaz
(ukazatel)
na instanci
třídy
68. TŘÍDY
• Datové složky
Nestatické datové složky
Deklarace může obsahovat inicializaci
public class A {
private int x = 10; private string s = "Text";
// ...
}
Takovéto přiřazení
hodnot proběhne ještě
před voláním
konstruktoru
Pokud nedojde k
inicializaci, inicializuje
překladač před voláním
konstruktoru hodnoty
na 0, false nebo null.
69. TŘÍDY
• Datové složky
Statické datové složky
Jako v C++ jsou společné pro všechny instance třídy.
Existují již od zavedení třídy do paměti (tedy bez nutnosti existence instance).
Deklarují se pomocí static.
Ty statické datové složky, které nejsou inicializovány před voláním konstruktoru
(existují statické konstruktory), překladač inicializuje hodnotou 0, false nebo
null.
Při použití mimo třídu je nutné je kvalifikovat jménem třídy.
70. TŘÍDY
• Datové složky
Neměnné datové složky
Konstanty
Musí se inicializovat přímo v deklaraci
Deklarace pomocí const
Je automaticky statická, static nelze použít
Lze takto deklarovat hodnotové datové typy (základní typy), výčtový typ a string. Pro
referenční typy (třídy, …) jej lze použít pouze k deklaraci proměnné inicializované null.
Deklarace pomocí readonly – složku lze inicializovat až konstruktorem, pak už
ji nelze měnit.
71. TŘÍDY
• Datové složky
Neměnné datové složky
Příklad:
https://goo.gl/WdetzM
class A {
const int x = 10;
readonly int y = 20;
public A(int y)
{
this.y = y; // OK
x = 20; // Chyba
}
public void Set(int y)
{
this.y = y; // Chyba
}
}
72. TŘÍDY
• Datové složky
Neměnné datové složky
Příklad:
https://goo.gl/eeckXC struct Struktura
{
public int x;
public void SetX(int x) { this.x = x; }
}
class Trida
{
public readonly int[] pole = new int[] {1, 2};
public readonly Struktura b;
}
class Program
{
static void Main(string[] args)
{
Trida a = new Trida();
a.pole[0] = 5; // OK
//a.b.x = 20; // Chyba
a.b.SetX(20); // OK
}
}
73. TŘÍDY
• Datové složky
Doporučení
Nestatické datové složky by se neměly deklarovat jako veřejné nebo chráněné.
Přístup k nim pak realizovat pomocí vlastností.
Pro předdefinovanou instanci třídy nebo struktury, která neobsahuje metody, jež
umožňují modifikovat její datové složky (angl. immutable type), se má deklarovat
veřejná statická datová složka s modifikátorem readonly.
74. TŘÍDY
• Metody
Odlišnosti od C++
Neexistuje obdoba inline metody.
Vedle předávání parametrů hodnotou či odkazem existují v C# ještě tzv. výstupní
parametry.
Metody v C# lze přetěžovat na základě způsobu předávání parametrů.
Nelze předepsat implicitní hodnoty parametrů.
Nelze využívat prototyp v těle třídy a deklaraci provést mimo. Ta musí být vždy v
těle třídy.
75. TŘÍDY
• Metody
Odlišnosti od C++
Syntaxe
modifikátorynep typ identifikátor ( seznam_parametrůnep ) tělo
modifikátory – přístupová práva, vyjadřují, zda jde o statickou, virtuální,
abstraktní, zapečetěnou, předefinovanou, zastiňující metodu nebo externí
metodu z klasické dynamické knihovny. Lze uvést též unsafe (nezabezpečený
kód metody).
typ – typ návratové hodnoty. Možno i void.
identifikátor - jmenovka metody. Nemusí být unikátní, pokud se liší
signatura.
Počet, pořadí, typ a
způsob předávání
parametrů.
76. TŘÍDY
• Metody
Odlišnosti od C++
Syntaxe
modifikátorynep typ identifikátor ( seznam_parametrůnep ) tělo
seznam_parametrů – seznam formálních parametrů metody. Možno vynechat.
tělo - obvykle blok příkazů. U abstraktních a externích metod je tělo tvořeno
středníkem.
77. TŘÍDY
• Metody
Nestatické metody
Nestatické metody (angl. instance methods) implementují
operace s jednotlivými instancemi. Volají se pro konkrétní
instanci. Jméno nestatické metody volané mimo její třídu
se kvalifikuje jménem instance její třídy.
V deklaraci není uveden modifikátor static.
V těle metody je k dispozici odkaz na aktuální instanci
vyjádřený klíčovým slovem this, stejně jako v C++.
Odkazem this lze kvalifikovat pouze nestatické složky
třídy.
79. TŘÍDY
• Metody
Statické metody
Statická metoda se deklaruje s modifikátorem static
Implementují operace s třídou jako celkem, ne instancemi.
Není k dispozici this a nelze pracovat s nestatickými složkami bez kvalifikace
instance.
80. TŘÍDY
• Metody
Statické metody
Příklad
class Program
{
void Run() // nestatická metoda
{
Console.WriteLine("Zavolána nestatická metoda Run");
}
static void Main(string[] args) // statická metoda
{
Program program = new Program();
program.Run();
}
}
81. TŘÍDY
• Metody
Předávání parametrů
V C# lze předávat parametry metody hodnotou nebo odkazem a používat
výstupní parametry. Lze také deklarovat metodu s proměnným počtem
parametrů - obdoba výpustky v C++.
Syntaxe
typ identifikátor
Typ – typ parametru.
Identifikátor – jméno parametru.
82. TŘÍDY
• Metody
Předávání parametrů hodnotou
Význam parametru předávaného hodnotou je stejný jako v C++ - vytváří se lokální
proměnná v těle metody, do které se uloží hodnota skutečného parametru.
V případě hodnotových parametrů se skutečný parametr nemění.
U referenčních typů se předává odkaz na instanci -> může dojít ke změně datové složky
odpovídající instance.
Skutečným parametrem může být jakýkoli výraz, který lze implicitní konverzí převést na
typ parametru.
83. TŘÍDY
• Metody
Předávání parametrů hodnotou
Příklad: https://goo.gl/tk5ReL
class TridaA
{
public int x, y;
public TridaA(int x, int y) { this.x = x; this.y = y; }
}
struct StrukturaB
{
public int x, y;
public StrukturaB(int x, int y) { this.x = x; this.y = y; }
}
class Program
{
static void f(TridaA a1, TridaA a2, StrukturaB b)
{
a1.x = b.x; // složka x se ve skutečném parametru změní
a2 = a1; // skutečný parametr se nezmění
b.y = a1.y; // skutečný parametr se nezmění
}
static void Main(string[] args)
{
TridaA a1 = new TridaA(10, 20), a2 = new TridaA(30, 40);
StrukturaB b = new StrukturaB(50, 60);
f(a1, a2, b);
// změna pouze u složky a1.x = 50
}
}
84. TŘÍDY
• Metody
Předávání parametrů odkazem
Význam předávání parametru odkazem je stejný jako v C++, syntaxe je ovšem
jiná – před typ se zapisuje modifikátor ref.
Syntaxe
ref typ identifikátor
Formální parametr v metodě představuje vlastně jen jiné
jméno pro skutečný parametr, takže veškeré operace
prováděné s formálním parametrem se ihned projeví v
hodnotě skutečného parametru.
Při volání metody se před skutečný parametr musí zapsat
modifikátor ref.
Skutečným parametrem musí být proměnná stejného typu,
jaký je uveden v deklaraci formálního parametru nebo
typu, který je potomkem typu formálního parametru.
85. TŘÍDY
• Metody
Předávání parametrů odkazem
Příklad
class Program
{
static void g(ref TridaA a1, ref TridaA a2, ref StrukturaB b)
{
a1.x = b.x; a2 = a1; // a2 se bude odkazovat na a1 b.y = a1.y;
}
static void Main(string[] args)
{
TridaA a1 = new TridaA(10, 20), a2 = new TridaA(30, 40);
StrukturaB b = new StrukturaB(50, 60);
g(ref a1, ref a2, ref b);
// všechny instance mají složky x = 50, y = 20
Console.ReadLine();
}
}
86. TŘÍDY
• Metody
Výstupní parametry
Výstupní parametry se liší od parametrů předávaných
hodnotou tím, že jako skutečný výstupní parametr lze
předat proměnnou, která nebyla inicializována. V metodě
se musí výstupní parametr inicializovat, i když byl
skutečný parametr před voláním této metody inicializován.
Před formálním i skutečným parametrem se musí zapsat
modifikátor out.
Syntaxe
out typ identifikátor
87. TŘÍDY
• Metody
Výstupní parametry
Příklad
class Program
{
static void f(int x, out int y)
{
// Console.WriteLine("y = " + y); // Chyba - y není inicializ.
y = x;
Console.WriteLine("y = " + y); // OK
}
static void Main(string[] args)
{
int x = 20, y;
f(x, out y); // proměnná x musí být inicializována
}
}
88. TŘÍDY
• Metody
Neznámý počet parametrů
Jestliže předem není známý počet a typ parametrů metody, lze v C# použít
modifikátor params. Tento modifikátor lze použít u posledního z formálních
parametrů metody. V normě C# se tento parametr nazývá parameter array.
Syntaxe
params typ_pole identifikátor
Typ pole – typ jednorozměrného pole. Nelze v něm použít
modifikátory ref a out.
Skutečným parametrem může být:
Pole odpovídajícího typu – parametr s modifikátorem params se chová
stejně jako parametr předávaný hodnotou.
Seznam výrazů oddělených čárkou, jejichž hodnoty lze implicitními
konverzemi převést na typ prvků pole formálního parametru.
89. TŘÍDY
• Metody
Neznámý počet parametrů
class Matematika
{
public static int Maximum(params int[] data)
{
if (data.Length == 0) return 0;
int max = data[0];
foreach (int a in data) {
if (a > max) max = a;
}
return max;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Maximum = {0}", Matematika.Maximum(5, 88, -3));
int[] pole = { 9, 8, 7 };
int max = Matematika.Maximum(pole);
Console.WriteLine("Maximum = {0}", max);
}
}
90. • Metody
Přetěžování
V C# lze deklarovat v jedné třídě metody se stejným
identifikátorem, pokud se liší v počtu, typu, pořadí nebo způsobu
předávání parametrů.
Lze deklarovat
void f() {}
void f(int x) {}
void f(char x) {}
void f(ref char x) {}
void f(char x) {}
void f(out char x) {}
TŘÍDY
91. • Metody
Přetěžování
Nelze deklarovat metody lišící se jen ref a out.
void f(ref char x) {}
void f(out char x) {} //chyba
Nelze rozlišit metody pouze podle typu návratové hodnoty nebo podle
modifikátoru params.
Pokud skutečné parametry neodpovídají, používají se pravidla pro
nalezení „nejlepší shody“.
stejný počet parametrů + nejsnažší implicitní konverze typů skutečných na
formální typy metody.
TŘÍDY
92. • Metody - doporučení
Výstupní parametry vždy uvádět až na konci seznamu parametrů metody
(kromě parametrů s modifikátorem params)
Přetížené metody by měly mít parametry stejného typu a názvu uvedené
ve stejném pořadí (kromě těch s modifikátory out a params, které by měly
být na konci).
TŘÍDY
93. • Metody - doporučení
Pokud mají být přetížené metody virtuální, má být deklarována jako
virtuální pouze jedna verze přetížené metody, která má největší počet
parametrů. Ostatní verze metody, by měly volat tuto verzi.
TŘÍDY
public void Write(string message, FileStream stream)
{
this.Write(message, stream, false);
}
public virtual void Write(string message, FileStream stream, bool closeStream)
{
// vlastní činnost
}
94. • Metody – doporučení
Pokud některý parametr metody je volitelný, měly by se vytvořit dvě
přetížené verze této metody, jedna s tímto parametrem a druhá bez tohoto
parametru.
Parametr referenčního typu, pro který je povolena hodnota null by se
neměl chápat jako volitelný parametr, ale jako parametr, pro nějž se má
použít nějaká implicitní hodnota.
TŘÍDY
95. • Externí metody
V C# lze volat i funkce napsané v C/C++ nebo v jiném programovacím
jazyce a uložené v klasické dynamické knihovně pro neřízený kód.
Tato funkce musí být deklarována v C# jako statická externí metoda s atributem
DllImport, ve kterém se uvede jméno souboru dynamické knihovny.
Takto lze volat i funkce z Windows API.
Syntaxe
[DllImport( knihovna )] modifikátorynep static extern typ identifikátor
(seznam_parametrůnep);
TŘÍDY
96. • Externí metody
Příklad
TŘÍDY
class Program
{
[DllImport("user32.dll")]
static extern int MessageBox(int windowHandle, string text,
string caption, uint type);
static void Main(string[] args)
{
MessageBox(0, "Ukázka volání funkce MessageBox z Windows
API",
"Hlášení", 0);
}
}
97. • Metoda Main
Vstupní bod konzolové i okenní aplikace.
Má 4 podoby:
static int Main() {}
static int Main(string[] args) {}
static void Main() {}
static void Main(string[] args) {}
Libovolný specifikátor přístupových práv.
Pokud je návratový typ int, vrací kód ukončení programu – jako v C++
TŘÍDY
98. • Metoda Main
Parametr args představuje parametry předávané z příkazové řádky.
Na rozdíl od C++ není nultým parametrem název programu.
Lze ji přetěžovat, ale jako vstupní bod může sloužit jen jedna z výše
uvedených.
Může se nacházet ve více třídách – nutno ale určit, která se použije jako
vstupní bod programu.
pomocí přepínače: /main:třída
pomocí menu: Project | Properties, část Application, rozevírací seznam Startup
object
TŘÍDY
99. • Podmíněné metody
Metodu s návratovým typem void lze deklarovat jako podmíněnou s
atributem Conditional.
Syntaxe
[ Conditional ( "jméno" ) ] deklarace_metody_typu_void
Jméno – identifikátor podmíněného symbolu deklarovaného pomocí direktivy #define.
Je-li identifikátor jméno definován, přeloží se tato metoda i všechna její volání stejně, jako
kdyby atribut Conditional nebyl u metody uveden.
Pokud identifikátor jméno není definován, překladač odstraní všechna volání této metody
ze zdrojových textů programu, ale metodu přeloží.
TŘÍDY
100. • Podmíněné metody
Příklad
TŘÍDY
#define LADĚNÍ
using System;
using System.Diagnostics;
class Ladění
{
[Conditional("LADĚNÍ")]
public static void Výpis(string s, int x)
{
Console.WriteLine("Proměnná {0} má hodnotu {1}", s, x);
}
}
class Program
{
static void Main(string[] args)
{
int a = 1, b = 2;
Ladění.Výpis("a", a); // #1
Ladění.Výpis("b", b); // #2
Console.WriteLine("Součet proměnných je {0}", a + b);
Console.ReadKey();
}
}
101. • Konstruktory
Podobně jako v C++ slouží k vytvoření a inicializaci instance.
Rozdíly oproti C++
V C# lze deklarovat statické konstruktory
V C# může konstruktor volat jiný konstruktor téže třídy
Konstruktor v C# nelze použít k implicitní konverzi
V C# neexistuje kopírovací konstruktor
V C# je konstruktor volán vždy explicitně pomocí new
TŘÍDY
102. • Konstruktory
instanční konstruktor
známý z C++
Syntaxe
modifikátorynep identifikátor ( seznam_parametrůnep ) inicializátornep tělo
Inicializátor
:this (seznam_parametrůnep)
:base (seznam_parametrůnep)
Modifikátory – přístupová práva
Identifikátor – shodný s názvem třídy, které je konstruktorem
TŘÍDY
Volání jiného konstruktoru téže třídy
Volání konstruktoru bezprostředního
předka třídy
103. • Konstruktory
instanční konstruktor
nedědí se
Pokud neexistuje uživatelem definovaný konstruktor, vytváří překladač
implicitní, veřejně přístupný konstruktor bez parametrů a s prázdným tělem.
TŘÍDY
104. • Konstruktory
instanční konstruktor
Příklad: https://goo.gl/bk5T9P
TŘÍDY
class Matice { double[,] a; public Matice(int m, int n) { a = new double[m, n]; }
public Matice(int m, int n, double hodnota) : this(m, n) { for (int i = 0; i <
a.GetLength(0); i++) { for (int j = 0; j < a.GetLength(1); j++ ) a[i, j] = hodnota;
}
}
public void Výpis() { ... }
}
class Program
{
static void Main(string[] args)
{
Matice matice = new Matice(3, 2);
matice.Výpis();
matice = new Matice(3, 2, 10.54);
matice.Výpis();
// Matice matice2 = new Matice();
// Chyba - třída nemá implicitní konstruktor
}
}
105. • Konstruktory
instanční konstruktor
doporučení
parametr konstruktoru vlastnosti (a jí případně odpovídající datové složky) by měl mít
stejný název jako vlastnost – rozdíl je pouze ve velikosti písmen. Parametr velbloudím a
veřejná/chráněná vlastnost pascalovským stylem.
TŘÍDY
106. • Konstruktory
statický konstruktor
Neexistuje v C++
Slouží k inicializaci statických složek
Syntaxe
static identifikátor ( ) tělo
identifikátor – shodný s názvem třídy
V těle (bloku příkazů) lze pracovat jen se statickými složkami třídy
Nedědí se
Nelze jej volat explicitně (volá jej program při zavedení třídy do paměti)
TŘÍDY
107. • Konstruktory
statický konstruktor
Nemá modifikátor přístupových práv
Neobsahuje parametry
TŘÍDY
108. • Konstruktory
statický konstruktor
Příklad
TŘÍDY
class Matice { double[,] a; static readonly int rozměr;
static Matice()
{
Console.Write("Zadej rozměr matice: ");
rozměr = Convert.ToInt32(Console.ReadLine());
}
public Matice()
{
// rozměr = 3; // Chyba
a = new double[rozměr, rozměr];
}
public Matice(double hodnota)
: this()
{
for (int i = 0; i < rozměr; i++) {
for (int j = 0; j < rozměr; j++) a[i, j] = hodnota;
}
}
// ...
}
109. • Destruktor
V nové normě C# je nazýván finalizér (finalizer).
Jiná úloha než v C++
V C# jde o zkratku metody finalize třídy object. Tu volá automatická
správa paměti při uvolnění instance z paměti.
Destruktor lze využít tedy např. k uvolnění jiných prostředků než je
operační paměť (otevřené soubory, síťová připojení)
Syntaxe
~ identifikátor ( ) tělo
identifikátor třídy, v němž je konstruktor deklarován
TŘÍDY
110. • Destruktor
Nemá přístupová práva
Nemá parametry
Nedědí se
Nelze jej volat explicitně
V C# se používají zřídka
V rozsáhlejších programech mohou způsobovat zdržení při automatickém úklidu
paměti. Objekty s destruktory nejsou odstraněny přímo, ale odkládají se stranou,
pak se volá jejich finalize metoda, a pak se teprve odstraňují.
Destruktory se zpravidla kombinují s metodou Dispose() rozhraní IDisposable
TŘÍDY
111. • Vlastnosti (properties)
V normě C++ neexistují. Lze se s nimi setkat v rámci některých rozšířeních
jazyka C++ (Borland C++ Builder).
Syntaktická zkratka pro dvojici přístupových metod.
Používá se prostřednictvím svého identifikátoru. Přiřazením hodnoty do
identifikátoru se volá jedna z přístupových metod. Ta může např. uložit
danou hodnotu do soukromé datové složky či provést i řadu jiných operací.
Při použití hodnoty vlastnosti se volá druhá z metod. Ta může vrátit
hodnotu uloženou v soukromé datové složce či hodnotu získanou např.
výpočtem.
TŘÍDY
112. • Vlastnosti (properties)
Syntaxe
modifikátorynep typ jméno { část_set část_getnep }
modifikátorynep typ jméno { část_get část_setnep }
Modifikátory - modifikátory přístupových práv a modifikátory vyjadřující,
zda jde o statickou, virtuální, abstraktní, zapečetěnou, předefinovanou
nebo zastiňující vlastnost.
Typ – typ hodnoty vlastnosti
Jméno – identifikátor vlastnosti
Část_set – přístupová metoda pro nastavení hodnoty vlastnosti
Část_get – přístupová metoda pro zjištění hodnoty
TŘÍDY
113. • Vlastnosti (properties)
Na pořadí uvedení části get a části set nezáleží.
Jednu z nich lze vynechat.
Vynecháním části set se získá vlastnost „jen pro čtení“.
Vynecháním části set se získá vlastnost „jen pro zápis“.
Syntaxe částí get a set
modifikátorynep get tělo
modifikátorynep set tělo
Tělo – blok příkazů, nebo jen středník u abstraktní vlastnosti.
Modifikátory - Jsou-li modifikátory u dané části uvedeny, musí reprezentovat
přístupové právo, které více omezuje přístup k dané části než modifikátory
přístupových práv pro vlastnost jako celek.
TŘÍDY
114. • Vlastnosti (properties)
Modifikátory přístupových práv
TŘÍDY
Ve vlastnosti Povolené mod. u get a set
public protected internal
internal
protected
private
protected internal internal
protected
private
internal private
protected private
private
115. • Vlastnosti (properties)
V těle části set existuje proměnná value typu shodného
s typem vlastnosti.
value obsahuje hodnotu přiřazovanou vlastnosti
Tělo části get musí obsahovat příkaz
return výraz;
ten poskytuje vrácenou hodnotu vlastnosti
TŘÍDY
116. • Vlastnosti (properties)
Příklad: https://goo.gl/i8pzgB
TŘÍDY
class KomplexCislo
{
private int real;
private int imag;
public KomplexCislo(int real, int imag)
{
this.real = real;
this.imag = imag;
}
public int Real
{
get { return real; }
set { real = value; }
}
public int Imag
{
get { return imag; }
set { imag = value; }
}
public double Abs
{
get { return Math.Sqrt(Real*Real + Imag*Imag); }
} }
class Program { static void Main(string[] args) {
KomplexCislo kc = new KomplexCislo(10, 20);
Console.WriteLine("Absolutní hodnota čísla ({0} + {1}i) je {2:F1}", kc.Real, kc.Imag, kc.Abs);
kc.Real = 3;
kc.Imag = 4;
Console.WriteLine("Absolutní hodnota čísla ({0} + {1}i) je {2:F1}", kc.Real, kc.Imag, kc.Abs);
Console.ReadKey();
} }
117. • Vlastnosti (properties)
Statické vlastnosti
Statická vlastnost je deklarována s modifikátorem static.
Lze ji použít, i v případě, že neexistuje žádná instance dané
třídy.
Při použití statické vlastnosti mimo její třídu se kvalifikuje
jménem její třídy.
Část get a část set statické vlastnosti může pracovat pouze
se statickými složkami dané třídy.
TŘÍDY
118. • Vlastnosti (properties)
Doporučení
Vlastnost by měla mít stejný název jako její odpovídající datová
složka.
Rozdíl je pouze ve velikosti písmen. Pro soukromou datovou
složku se používá velbloudí styl a pro veřejnou a chráněnou
vlastnost pascalovský styl.
Pokud se jedná o řádově pomalejší operaci, než je nastavení
hodnoty do datové složky třídy (např. přístup k souboru),
doporučuje se použít místo vlastnosti metodu.
Nedoporučuje se deklarovat vlastnosti, které umožňují pouze
nastavení hodnoty (to lze provést metodou).
Nastavení vlastností dané třídy by nemělo být závislé na pořadí.
Pokud při nastavení vlastnosti dojde k vyvolání výjimky, měla by
si vlastnost uchovat předchozí hodnotu.
Část get by neměla vyvolávat výjimku.
TŘÍDY
119. • Události
Jazyk C# oproti C++ nabízí jednotný mechanismus zpracování událostí.
Založeno na návrhovém vzoru vydavatel – předplatitel (publisher - subscriber).
Instance, v níž může událost vzniknout (vydavatel), si vede
seznam instancí, jež mají zájem na tuto událost reagovat
(předplatitelů).
Instance, jež má zájem reagovat na určitou událost, tedy
předplatitel, si u vydavatele registruje metodu, která se o
reakci postará. K tomu použije delegát.
Nastane-li událost, vyrozumí o ní vydavatel své předplatitele
tím, že zavolá jejich registrované metody.
TŘÍDY
120. • Události
Handler a údaje o události
Metody, které reagují na události, se označují jako handlery.
Jsou vždy typu void.
Mají dva parametry (object – odkaz na instanci jež vyvolala událost a
System.EventArgs).
Signatura
void Stisk(object sender, EventArgs e) {}
Knihovna BCL obsahuje řadu potomků třídy EventArgs pro běžné typy
událostí, jako je stisknutí tlačítka myši, stisknutí klávesy apod.
Pokud událost umožňuje stornování činnosti, druhý parametr handleru
by měl být typu CancelEventArgs (nebo jeho potomek). Typ
CancelEventArgs obsahuje jednu vlastnost Cancel, která poskytuje
nebo nastavuje hodnotu, udávající, zda činnost, která je s událostí
spojená, by měla být stornována.
TŘÍDY
121. • Události
Handler a údaje o události
Pro zpracování událostí nabízí knihovna BCL celou řadu
předdefinovaných delegátů. Lze si však deklarovat i vlastní.
Identifikátor delegátu by měl obsahovat příponu EventHandler.
Potomek třídy EventArgs by měl obsahovat příponu EventArgs.
Delegát může obsahovat ukazatele na více handlerů.
TŘÍDY
delegate void NecoSeStaloEventHandler(object sender, MojeEventArgs e);
122. • Události
Deklarace události
Jako složka třídy
Syntaxe
modifikátorynep event typ jméno ;
modifikátorynep event typ jméno { části_add_remove }
Modifikátory – modifikátory přístupových práv a
modifikátory vyjadřující, zda jde o statickou, virtuální,
abstraktní, zapečetěnou, předefinovanou nebo zastiňující
událost.
Typ – identifikátor delegátu.
Jméno – jméno (identifikátor) události. Zpravidla odpovídá
identifikátoru typ bez přípony EventHandler.
TŘÍDY
123. • Události
Deklarace události
Klíčové slovo event zamezí vyvolání události mimo třídu, v níž je
událost deklarována.
Mimo třídu události lze používat pouze operátory += a -= pro
registraci/zrušení registrace handleru.
Událost je tedy vícenásobný delegát, který nelze zavolat mimo jeho
třídu.
Událost by měla vyvolávat chráněná virtuální metoda třídy, v níž je
událost deklarována.
Název této metody by měl být ve tvaru OnJmeno, kde Jmeno je jméno
události. Ta má jeden parametr odpovídající druhému parametru události
(typu EventArgs, případně jeho potomka).
První parametr vyvolané události by neměl mít hodnotu null,
kromě statické události. Druhý parametr by neměl být nikdy null.
Třída EventArgs nabízí statickou datovou složku jen pro čtení
Empty, která by se měla použít místo vytvoření nové instance této
třídy.
TŘÍDY
124. • Události – Příklad: https://goo.gl/D5YlSk
TŘÍDY
public delegate void ZmenaSouradnicEventHandler(object sender,
EventArgs e);
class Bod
{
private int x;
private int y;
public event ZmenaSouradnicEventHandler ZmenaSouradnic;
public int X
{ get { return x; }
set
{ if (x != value)
{ x = value;
OnZmenaSouradnic(EventArgs.Empty);
} } }
public int Y
{ get { return y; }
set
{ if (y != value)
{ y = value;
OnZmenaSouradnic(EventArgs.Empty);
} } }
public Bod(int x, int y)
{ this.x = x;
this.y = y;
}
protected virtual void OnZmenaSouradnic(EventArgs e)
{ ZmenaSouradnicEventHandler handler = ZmenaSouradnic;
if (handler != null) handler(this, e);
} }
class Obrazek
{
public static void ZmenaSouradnic(object sender, EventArgs e)
{ Console.WriteLine("Došlo ke změně souřadnic bodu");
Console.WriteLine("Nové souřadnice bodu jsou: x = {0}, y =
{1}", (sender as Bod).X, (sender as Bod).Y);
} }
class Program
{
static void Main(string[] args)
{
Bod bod = new Bod(10, 20);
bod.ZmenaSouradnic += new
ZmenaSouradnicEventHandler(Obrazek.ZmenaSou
radnic);
// dtto od verze .NET 2.0:
// bod.ZmenaSouradnic +=
Obrazek.ZmenaSouradnic;
bod.X = 30;
// Chyba - nelze volat událost
mimo její třídu:
//
bod.ZmenaSouradnic(typeof(Program), new
EventArgs());
Console.ReadKey();
}
}
125. • Události - Příklad
V metodě OnZmenaSouradnic je vytvořena kopie události, aby nevznikla
kolize při přístupu k události z více podprocesů. Pokud by se nevytvořila
kopie, tak by po vyhodnocení výrazu v příkazu if, který testuje zda událost
není null, mohl jiný podproces zrušit registraci handleru této události a
pokud se jednalo o jediného předplatitele události, událost by měla
hodnotu null a při jejím vyvolání by vznikla výjimka typu
System.NullReferenceException. Lokální kopie události se sice
odkazuje na stejnou instanci vícenásobného delegátu, ale pokud se k
události registruje další handler, lokální kopie se již bude odkazovat na
jinou instanci.
TŘÍDY
126. • Události jako vlastnosti
Obsahuje-li třída větší množství událostí a jejich handlerů, může být
rozumné deklarovat je jako vlastnosti.
Umožňuje použít vlastní způsob ukládání handlerů, např. do hešovací
tabulky nebo jiné kolekce.
Událost se deklaruje jako vlastnost také v případě, pokud je potřebné
ošetřovat volání každého zaregistrovaného handleru zvlášť.
Syntaxe
add blok //přístupová metoda pro přidání handleru do kolekce handlerů
remove blok //přístupová metoda pro odebrání handleru z kolekce handlerů
TŘÍDY
127. • Události jako vlastnosti – příklad: https://goo.gl/bNKlxD
TŘÍDY
class Bod
{
private int x;
private int y;
private ZmenaSouradnicEventHandler zmenaSouradnic;
public event ZmenaSouradnicEventHandler ZmenaSouradnic
{
add
{
lock (this) zmenaSouradnic += value;
}
remove
{
lock (this) zmenaSouradnic -= value;
}
}
protected virtual void OnZmenaSouradnic(EventArgs e)
{
ZmenaSouradnicEventHandler handler = zmenaSouradnic;
if (handler != null) handler(this, e);
}
// zbytek stejný jako v předchozím příkladu