Professional Documents
Culture Documents
Csharp
Csharp
Csharp
-2-
Tartalomjegyzk
1
Bevezet .........................................................................................................................9
1.1 A jegyzet jellsei ....................................................................................................9
1.2
MSIL/CIL ....................................................................................................... 10
2.1.2
Fordts s futtats........................................................................................... 11
2.1.3
BCL ................................................................................................................ 11
2.2
2.3
2.3.1
SSCLI ............................................................................................................. 12
2.3.2
Mono............................................................................................................... 12
2.3.3
DotGNU.......................................................................................................... 13
Kulcsszavak .................................................................................................... 15
3.1.2
Megjegyzsek ................................................................................................. 16
3.2
4
Nvterek ................................................................................................................. 17
Vltozk ....................................................................................................................... 18
4.1 Deklarci s definci ........................................................................................... 18
4.2
Tpusok .................................................................................................................. 18
4.3
4.4
4.5
Referencik ............................................................................................................ 22
4.6
4.7
Konstansok............................................................................................................. 25
4.8
4.9
Null tpusok............................................................................................................ 27
4.10
5
Opertorok.................................................................................................................... 30
5.1 Opertor precedencia .............................................................................................. 30
5.2
5.3
5.4
5.5
5.6
5.7
5.8
6
6.3
Ciklus ..................................................................................................................... 45
6.2
6.3.1
Yield ............................................................................................................... 50
6.3.2
7.3
7.4
7.2
Tpuskonverzik ........................................................................................................... 64
8.1 Ellenrztt konverzik ........................................................................................... 64
Is s as .................................................................................................................... 65
8.3
Karakterkonverzik ................................................................................................ 66
8.2
Tmbk ........................................................................................................................ 67
9.1 Tbbdimenzis tmbk .......................................................................................... 68
10
Stringek ........................................................................................................................ 71
10.1
Metdusok .......................................................................................................... 72
10.2
StringBuilder ...................................................................................................... 73
10.3
11
Szigetek .............................................................................................................. 77
11.3
tlaghmrsklet ................................................................................................ 79
11.4
Buborkrendezs................................................................................................. 79
12
Osztly ............................................................................................................... 81
12.3
12.4
Lthatsg .......................................................................................................... 82
12.5
Egysgbezrs .................................................................................................... 83
12.6
rklds ........................................................................................................... 83
13
Osztlyok...................................................................................................................... 85
13.1
Konstruktorok ..................................................................................................... 86
13.2
Adattagok ........................................................................................................... 89
13.3
13.4
13.5
13.6
13.7
Destruktorok ....................................................................................................... 93
14.3
15
16
17
17.3
17.4
17.5
18
18.3
18.4
18.5
19
19.3
19.4
20
20.2
20.3
20.4
21
22
22.2
22.3
22.4
22.5
23
Kivtelkezels............................................................................................................. 154
23.1
Kivtel hierarchia .............................................................................................. 156
23.2
23.3
23.4
24
24.3
25
26.3
26.4
26.5
26.6
26.8
27
27.3
27.4
28
29
29.2
30
30.3
30.5
30.6
30.7
31
32
32.3
32.4
32.5
32.6
33
34
34.3
35
Kivlaszts........................................................................................................ 251
35.4
35.5
35.7
35.8
35.9
35.10
35.11
35.12
35.12.1
35.12.2
35.12.3
35.12.4
35.12.5
AsSequential.............................................................................................. 274
36
36.3
36.4
37
36.2
-8-
Bevezet
Napjainkban egyre nagyobb teret nyer a .NET Framework s egyik f nyelve a C#.
Ez a jegyzet abbl a clbl szletett, hogy megismertesse az olvasval ezt a
nagyszer technolgit.
A jegyzet a C# 2.0, 3.0 s 4.0 verzijval foglalkozik, az utbbi kett ltal bevezetett
j eszkzket az adott rsz kln jelli. Nhny fejezet felttelez olyan tudst, amely
alapjt egy ksbbi rsz kpezi, ezrt ne essen ktsgbe a kedves olvas, ha
valamit nem rt, egyszeren olvasson tovbb s trjen vissza a krdses anyaghoz,
ha rtallt a vlaszra. A jegyzet megrtshez nem szksges programozni tudni,
viszont alapvet informatikai ismeretek (pl. szmrendszerek) jl jnnek.
A jegyzethez tartoz forrskdok letlthetek a kvetkez webhelyrl:
http://cid-283edaac5ecc7e07.skydrive.live.com/browse.aspx/Nyilv%C3%A1nos/Jegyzet
A jegyzet teljes tartalma a Creative Commons Nevezd meg!-Ne add el! 2.5
Magyarorszg liszensze al tartozik. Szabadon mdosthat s terjeszthet a forrs
feltntetsvel.
A jegyzet ingyenes, mindennem rtkestsi ksrlet tiltott s a szerz
beleegyezse nlkl trtnik!
-9-
2.1.1 MSIL/CIL
A hagyomnyos programnyelveken mint pl. a C++ megrt programok n. natv
kdra fordulnak le, vagyis a processzor szmra kis tlzssal azonnal
rtelmezhetek.
A .NET (akrcsak a Java) ms ton jr, a fordt elszr egy kztes nyelvre
(Intermediate Language) fordtja le a forrskdot. Ez a nyelv a .NET vilgban az
- 10 -
2.1.3 BCL
A .NET Framework teleptsvel a szmtgpre kerl tbbek kztt a BCL
(Base Class Library), ami az alapvet feladatok (file olvass/ rs, adatbzis kezels,
adatszerkezetek, stb) elvgzshez szksges eszkzket tartalmazza. Az sszes
tbbi knyvtr (ADO.NET, WCF, stb) ezekre pl.
2.3.1 SSCLI
Az SSCLI (Shared Source Common Language Infrastructure) vagy korbbi nevn
Rotor a Microsoft ltal fejlesztett nylt forrs, keresztplatformos vltozata a .NET
Frameworknek (teht nem az eredeti lebuttott vltozata). Az SSCLI Windows,
FreeBSD s Mac OSX rendszereken fut.
Az SSCLI t kimondottan tanulsi clra ksztette a Microsoft, ezrt a liszensze
engedlyez mindenfajta mdostst, egyedl a piaci rtkestst tiltja meg. Ez a
rendszer nem szolgltatja az eredeti keretrendszer teljes funkcionalitst, jelen
pillanatban valamivel a .NET 2.0 mgtt jr.
Az SSCLI projekt jelen pillanatban lellni ltszik. Ettl fggetlenl a forrskd s a
hozz tartoz dokumentcik rendelkezsre llnak, letlthetek a kvetkez
webhelyrl:
http://www.microsoft.com/downloads/details.aspx?FamilyId=8C09FD61-3F26-4555-AE173121B4F51D4D&displaylang=en
2.3.2 Mono
A Mono projekt szlatyja Miguel de Icaza, 2000 ben kezdte meg a fejlesztst s
egy vvel ksbb mutatta be ez els kezdetleges C# fordtt. A Ximian (amelyet
Icaza s Nat Friedman alaptott) felkarolta az tletet s 2001 jliusban hivatalosan
is elkezddtt a Mono fejlesztse. 2003 ban a Novell felvsrolta a Ximian t, az
1.0 verzi mr Novell termkknt kszlt el egy vvel ksbb.
A Mono elrhet Windows, Linux, UNIX, BSD, Mac OSX s Solaris rendszereken is.
Napjainkban a Mono mutatja a leggretesebb fejldst, mint a Microsoft .NET
- 12 -
2.3.3 DotGNU
A DotGNU a GNU projekt rsze, amelynek clja egy ingyenes s nylt alternatvt
nyjtani a Microsoft implementci helyett. Ez a projekt szemben a Mono val
nem a Microsoft BCL lel val kompatibilitst helyezi eltrbe, hanem az eredeti
szabvny pontos s tkletes implementcijnak a ltrehozst. A DotGNU sajt
CLI megvalstsnak a Portable .NET nevet adta. A jegyzet rsnak idejn a
projekt lellni ltszik.
A DotGNU hivatalos oldala: http://www.gnu.org/software/dotgnu/
- 13 -
belpsi pontja lesz. Minden egyes C# program a Main fggvnnyel kezddik, ezt
mindenkppen ltre kell hoznunk. Vgl meghvjuk a Console osztlyban lv
WriteLine s ReadKey fggvnyeket. Elbbi kirja a kpernyre a paramtert, utbbi
vr egy billenty letsre.
Ebben a bekezdsben szerepel nhny (sok) kifejezs, amik ismeretlenek lehetnek,
de a jegyzet ksbbi fejezeteiben mindenre fny derl majd.
3.1 A C# szintaktikja
Amikor egy programozsi nyelv szintaktikjrl beszlnk, akkor azokra a
szablyokra gondolunk, amelyek megszabjk a forrskd felptst. Ez azrt fontos,
mert az egyes fordtprogramok csak ezekkel a szablyokkal ltrehozott kdot tudjk
rtelmezni.
A C# gynevezett C-stlus szintaxissal rendelkezik (azaz a C programozsi nyelv
szintaxist veszi alapul), ez hrom fontos szablyt von maga utn:
Az egyes utastsok vgn pontosvessz (;) ll
A kis- s nagybetk klnbz jelentsggel brnak, azaz a program s
Program azonostk klnbznek. Ha a fenti kdban Console.WriteLine
helyett console.writeline t rtunk volna, akkor a program nem fordulna le.
A program egysgeit (osztlyok, metdusok, stb.) n. blokkokkal jelljk ki,
kapcsos zrjelek ({ s }) segtsgvel.
3.1.1 Kulcsszavak
Szinte minden programnyelv definil kulcsszavakat, amelyek specilis jelentsggel
brnak a fordt szmra. Ezeket az azonostkat a sajt meghatrozott jelentskn
kvl nem lehet msra hasznlni, ellenkez esetben a fordt hibt jelez. Vegynk
pldul egy vltozt, aminek az int nevet akarjuk adni. Az int egy beptett tpus a
neve is, azaz kulcssz, teht nem fog lefordulni a program.
int int;//hiba
- 15 -
A C# 77 kulcsszt ismer:
abstract
as
base
bool
break
byte
case
catch
char
checked
class
const
continue
decimal
default
delegate
do
double
else
enum
event
explicit
extern
false
finally
fixed
float
for
foreach
goto
If
implicit
In
int
interface
internal
Is
lock
long
namespace
new
null
object
operator
out
override
params
private
protected
public
readonly
ref
return
sbyte
sealed
short
Sizeof
stackalloc
Static
String
Struct
Switch
This
Throw
True
Try
Typeof
Uint
Ulong
unchecked
unsafe
ushort
using
virtual
volatile
void
while
Ezeken kvl ltezik mg 23 azonost, amelyeket a nyelv nem tart fenn specilis
hasznlatra, de klnleges jelentssel brnak. Amennyiben lehetsges, kerljk a
hasznlatukat hagyomnyos vltozk, metdusok, osztlyok ltrehozsnl:
add
ascending
by
descending
equals
from
get
global
group
in
into
join
let
on
orderby
partial
Remove var
Select where
Set
yield
Value
3.1.2 Megjegyzsek
A forrskdba megjegyzseket tehetnk. Ezzel egyrszt zeneteket hagyhatunk (pl.
egy metdus lersa) magunknak vagy a tbbi fejlesztnek, msrszt a kommentek
segtsgvel dokumentcit tudunk generlni, ami szintn az els clt szolglja, csak
ppen lvezhetbb formban.
Megjegyzseket a kvetkezkppen hagyhatunk:
using System;
class HelloWorld
{
static public void Main()
{
Console.WriteLine("Hello C#"); // Ez egy egysoros komment
Console.ReadKey();
/* Ez
egy
tbbsoros komment */
}
}
- 16 -
/* */
3.2 Nvterek
A .NET Framework osztlyknyvtrai szerny becsls szerint is legalbb tzezer
nevet, azonostt tartalmaznak. Ilyen nagysgrenddel elkerlhetetlen, hogy a nevek
ne ismtldjenek. Ekkor egyrszt nehz eligazodni kzttk, msrszt a fordt sem
tudn, mikor mire gondolunk. Ennek a problmnak a kikszblsre hoztk ltre a
nvterek fogalmt. Egy nvtr tulajdonkppen egy virtulis doboz, amelyben a
logikailag sszefgg osztlyok, metdusok, stb. vannak. Nyilvn knnyebb
megtallni az adatbzis-kezelshez szksges osztlyokat, ha valamilyen kifejez
nev nvtrben vannak (pl.System.Data).
Nvteret magunk is definilhatunk, a namespace kulcsszval:
namespace MyNameSpace
{
}
- 17 -
Vltozk
4.2 Tpusok
A C# ersen (statikusan) tpusos nyelv, ami azt jelenti, hogy minden egyes vltoz
tpusnak ismertnek kell lennie fordtsi idben, ezzel biztostva azt, hogy a program
pontosan csak olyan mveletet hajthat vgre amire valban kpes. A tpus hatrozza
meg, hogy egy vltoz milyen rtkeket tartalmazhat, illetve mekkora helyet foglal a
memriban.
A kvetkez tblzat a C# beptett tpusait tartalmazza, mellettk ott a .NET
megfeleljk, a mretk s egy rvid lers:
- 18 -
C# tpus
.NET tpus
Mret (byte)
byte
System.Byte
char
bool
System.Char
System.Boolean
2
1
sbyte
System.SByte
short
System.Int16
ushort
System.Uint16
int
System.Int32
uint
System.Uint32
float
System.Single
double
System.Double
decimal
long
ulong
string
object
System.Decimal
System.Int64
System.Uint64
System.String
System.Object
16
8
8
N/A
N/A
Lers
(radsul ezt azonnal meg is kell tennnk!), az gy fog viselkedni, mint az ekvivalens
tpus. Az ilyen vltozk tpusa nem vltoztathat meg, de a megfelel
tpuskonverzik vgrehajthatak.
int
var
z =
var
Metduson bell, loklisan deklarlt rtktpusok a stack-be kerlnek, a referenciatpuson bell adattagknt deklarlt rtktpusok pedig a heap-ben foglalnak helyet.
Nzznk nhny pldt!
using System;
class Program
{
static public void Main()
{
int x = 10;
}
}
Ebben a programban xet loklisan deklarltuk egy metduson bell, ezrt biztosak
lehetnk benne, hogy a verembe fog kerlni.
class MyClass
{
private int x = 10;
}
Osztlyok (class)
Interfsz tpusok (interface)
Delegate tpusok (delegate)
Stringek
- 21 -
4.5 Referencik
Az rtk- illetve referencia-tpusok kztti klnbsg egy msik aspektusa az,
ahogyan a forrskdban hivatkozunk rjuk. Vegyk a kvetkez kdot:
int x = 10;
int y = x;
Itt ugyanaz trtnik, mintha rgtn az x vltozt adnnk t a metdusnak csak ppen
egy lpssel hamarabb elksztettk x referencia-tpus klnjt.
Az unboxing (vagy kidobozols) a boxing ellentte, vagyis a bedobozolt
rtktpusunkbl kinyerjk az eredeti rtkt:
int x = 0;
object obj = x; // bedobozolva
int y = (int)obj; // kidobozolva
- 24 -
A kimenet 10 illetve 20 lesz. Vegyk szre azt is, hogy z n konverzit kellett
vgrehajtanunk az sszeadshoz, de az rtkadshoz nem (elszr kidobozoltuk,
sszeadtuk a kt szmot, majd az eredmnyt visszadobozoltuk).
4.7 Konstansok
A const tpusmdost kulcssz segtsgvel egy objektumot konstanss,
megvltoztathatatlann tehetnk. A konstansoknak egyetlen egyszer adhatunk (s
ekkor ktelez is adnunk) rtket, mgpedig a deklarcinl. Brmely ksbbi
prblkozs fordtsi hibt okoz.
const int x; // Hiba
const int x = 10; // Ez j
x = 11; // Hiba
Ezutn gy hasznlhatjuk:
- 25 -
Animal b = Animal.Tiger;
if(b == Animal.Tiger) // Ha b egy tigris
{
Console.WriteLine("b egy tigris...");
}
Enum tpust csakis metduson kvl (osztlyon bell, vagy nll tpusknt)
deklarlhatunk, ellenkez esetben a program nem fordul le:
using System;
class Program
{
static public void Main()
{
enum Animal { Cat = 1, Dog = 3, Tiger, Wolf }
}
}
Ilyen mdon csakis a beptett egsz numerikus tpusokat hasznlhatjuk (pl. byte,
long, uint, stb...)
Azok az nevek amelyekhez nem rendeltnk rtket implicit mdon, az ket
megelz nv rtktl szmtva kapjk meg azt, nvekv sorrendben. gy a lenti
pldban Tiger rtke ngy lesz:
using System;
class Program
{
enum Animal { Cat = 1, Dog = 3, Tiger, Wolf }
static public void Main()
{
Animal a = Animal.Tiger;
Console.WriteLine((int)a);
}
}
rtktpusok pedig az ltaluk trolt adatot reprezentljk, ezrt k nem vehetnek fel
null rtket.
Ahhoz, hogy meg tudjuk llaptani, hogy egy rtktpus mg nem inicializlt, egy
specilis tpust, a nullable tpust kell hasznlnunk, amit a rendes tpus utn rt
krdjellel jelznk:
int? i = null; // ez mr mkdik
Egy nullable tpusra val konverzi implicit mdon (kln krs nlkl) megy vgbe,
mg az ellenkez irnyban explicit konverzira lesz szksgnk (vagyis ezt tudatnunk
kell a fordtval):
int y = 10;
int? x = y; // implicit konverzi
y = (int)x; // explicit konverzi
- 28 -
class Test
{
public void Method(string s)
{
}
}
Ha a fenti metdust meg akarjuk hvni, akkor meg kell adnunk szmra egy string
tpus paramtert is. Kivve, ha a dynamicot hasznljuk:
static public void Main()
{
dynamic t = new Test();
t.Method(); // ez lefordul
}
A fenti forrskd minden tovbbi nlkl lefordul, viszont futni nem fog.
A konstruktorok nem tartoznak az tverhet metdusok kz, akr hasznltuk a
deklarcinl a dynamicot, akr nem. A paramtereket minden esetben ktelez
megadnunk, ellenkez esetben a program nem fordul le.
Br a fenti tesztek szrakoztatak, valjban nem tl hasznosak. A dynamic
hagyomnyos objektumokon val hasznlata lnyegben nemcsak tlthatatlann
teszi a kdot, de komoly teljestmnyproblmkat is okozhat, ezrt mindenkppen
kerljk el az ilyen szitucikat!
A dinamikus tpusok igazi haszna a ms programnyelvekkel klnsen a script
alap nyelvekkel val egyttmkdsben rejlik. A dynamic kulcssz mgtt egy
komoly platform, a Dynamic Language Runtime (DLR) ll (termszetesen a dynamic
mellett j nhny osztly is helyett kapott a csomagban). A DLR olyan tpustalan,
azaz gyengn tpusos nyelvekkel tud egyttmkdni, mint a Lua, JavaScript, PHP,
Python vagy Ruby.
- 29 -
Opertorok
- 30 -
(10 * 5) + 1
A C# nyelv precedencia szerint 14 kategriba sorolja az opertorokat (a kisebb
sorszmt fogja a fordt hamarabb kirtkelni):
1. Zrjel, adattag hozzfrs (pont (.) opertor), metdushvs, postfix
inkrementl s dekrementl opertorok, a new opertor, typeof, sizeof,
checked s unchecked
2. Pozitv s negatv opertorok (x = -5), logika- s binris tagads, prefix
inkrementl s dekrementl opertorok, explicit tpuskonverzi
3. Szorzs, maradkos s maradk nlkli oszts
4. sszeads, kivons
5. Bit-eltol (>> s <<) opertorok
6. Kisebb (vagy egyenl), nagyobb (vagy egyenl), as, is
7. Egyenl s nem egyenl opertorok
8. Logikai S
9. Logikai XOR
10. Logikai VAGY
11. Feltteles S
12. Feltteles VAGY
13. Feltteles opertor ( ? : )
14. rtkad opertor, illetve a rvid formban hasznlt opertorok (pl: x +=y)
Ltrehoztunk egy int tpus vltozt, elneveztk x nek, majd kezdrtknek 10et
adtunk. Termszetesen nem ktelez a deklarcinl megadni a defincit (amikor
meghatrozzuk, hogy a vltoz milyen rtket kapjon), ezt el lehet halasztani:
int x;
x = 10;
Ettl fggetlenl a legtbb esetben ajnlott akkor rtket adni egy vltoznak, amikor
deklarljuk (persze ez inkbb csak eszttikai krds, a fordt lesz annyira okos,
hogy ugyanazt generlja le a fenti kt kdrszletbl).
Egy vltoznak nem csak konstans rtket, de egy msik vltozt is rtkl
adhatunk, de csakis abban az esetben, ha a kt vltoz azonos tpus, illetve ha
ltezik megfelel konverzi (a tpuskonverzikkal egy ksbbi fejezet foglalkozik).
- 31 -
int x = 10;
int y = x; // y rtke most 10
x nagyobb, mint y
x nagyobb vagy egyenl, mint y
x kisebb, mint y
x kisebb vagy egyenl, mint y
x egyenl y-nal
x nem egyenl y-nal
- 33 -
A vagy (||) opertor akkor trt vissza igaz rtket, ha az operandusai kzl
valamelyik igaz vagy nagyobb, mint nulla. Ez a program is ugyanazt csinlja, mint
az elz, a klnbsg a felttelben van. Lthat, hogy k biztosan nem igaz (hiszen
ppen eltte kapott hamis rtket).
A VAGY igazsgtblzata:
A
B
Eredmny
hamis hamis
hamis
hamis igaz
igaz
igaz hamis
igaz
igaz
igaz
igaz
Az eredmny kirtkelse az n. lusta kirtkels (vagy rvidzr) mdszervel
trtnik, azaz a program csak addig vizsglja a felttelt, amg muszj. Tudni kell azt
is, hogy a kirtkels mindig balrl jobbra halad, ezrt pl. a fenti pldban k soha
nem fog kirtkeldni, mert l van az els helyen, s mivel igaz rtket kpvisel,
ezrt a felttel is biztosan teljesl.
A harmadik a tagads (!):
using System;
public class RelOp
{
static public void Main()
{
int x = 10;
- 34 -
A logikai S:
if(l == true & k == true)
{
Console.WriteLine("Igaz");
}
- 35 -
hogy
az
igazsgtblt
hasznltuk
az
eredmny
Plda:
using System;
public class Program
{
static public void Main()
{
Console.WriteLine(10 & 2);
//1010 & 0010 = 0010 = 2
}
}
- 36 -
Plda a VAGY-ra:
using System;
public class Program
{
static public void Main()
{
Console.WriteLine(10 | 2);
// 1010 | 0010 = 1010 = 10
}
}
Biteltols balra: a kettes szmrendszerbeli alak fels bitjt eltoljuk, majd a jobb
oldalon keletkez res bitet nullra lltjuk. Az opertor jele: <<.
10001111 LEFT SHIFT
100011110
Plda:
using System;
public class Program
{
static public void Main()
{
int x = 143;
Console.WriteLine(x << 1);
// 10001111 (=143) << 1 = 100011110 = 286
}
}
- 37 -
Ez a metdus a konvertls utn csak a hasznos rszt fogja visszaadni, ezrt fog
az int tpus - egybknt 32 bites - vltoz csak 4 biten megjelenni (hiszen a 10 egy
pontosan 4 biten felrhat szm).
A char tpus numerikus rtkre konvertlsakor az Unicode tblban elfoglalt helyt
adja vissza. Ez az a karakter esetben 97 (tzes szmrendszer), 1100001 (kettes
szr.) vagy 0061 (tizenhatos szr.) lesz. Ez utbbinl is csak a hasznos rszt kapjuk
vissza, hiszen a fels nyolc bit itt nullkbl ll.
Vegyk szre, hogy amg a balra val eltols tnylegesen fizikailag hozztett az
eredeti szmunkhoz, addig a jobbra tols elvesz belle, hiszen a fellre rkez
nulla bitek nem hasznosulnak az eredmny szempontjbl. rtelemszeren a balra
tols ezrt mindig nvelni, a jobbra tols pedig mindig cskkenteni fogja az
eredmnyt.
Ennl is tovbb mehetnk, felfedezve a biteltolsok valdi hasznt: egy n bittel balra
tols megfelel az alapszm 2 az nedik hatvnyval val szorzsnak:
143 << 1 = 143 * (2^1) = 286
143 << 2 = 143 * (2^2) = 572
Ugyangy a jobbra tols ugyanazzal a hatvnnyal oszt (nullra kerektssel):
143 >> 1 = 143 / (2^1) =71
143 >> 2 = 143 / (2^2) = 35
Amikor olyan programot ksztnk, amely ersen pt kettvel vagy hatvnyaival val
szorzsra/osztsra, akkor ajnlott bitmveleteket hasznlni, mivel ezeket a
processzor sokkal gyorsabban vgzi el, mint a hagyomnyos szorzst
(tulajdonkppen a szorzs a processzor egyik leglassabb mvelete).
- 38 -
Az x nev vltozt megnveltk tzzel. Csakhogy van egy kis baj: ez a megolds
nem tl hatkony. Mi trtnik valjban? Elsknt rtelmezni kell a jobb oldalt, azaz
ki kell rtkelni xet, hozz kell adni tzet s eltrolni a veremben. Ezutn ismt
kirtkeljk xet, ezttal a bal oldalon.
Szerencsre van megolds, mgpedig az n. rvid forma. A fenti sorbl ez lesz:
x + = 10;
- 39 -
A vltozn meghvott GetType metdus a vltoz tpust adja vissza (ez egy
System.Objecthez tartoz metdus, gy a hasznlathoz dobozolni kell az
objektumot).
- 40 -
Ez a program ngyet fog kirni, hiszen az int tpus 32 bites, azaz 4 byte mret tpus.
A programot az unsafe kapcsolval kell lefordtanunk:
csc /unsafe main.cs
- 41 -
Vezrlsi szerkezetek
Vezrlsi szerkezetnek
konstrukcikat nevezzk.
program
utastsainak
sorrendisgt
szablyoz
6.1 Szekvencia
A legegyszerbb vezrlsi szerkezet a szekvencia. Ez tulajdonkppen egyms utn
megszabott sorrendben vgrehajtott utastsokbl ll.
6.2 Elgazs
Gyakran elfordul, hogy meg kell vizsglnunk egy lltst, s attl fggen, hogy igaz
vagy hamis, a programnak ms-ms utastst kell vgrehajtania. Ilyen esetekben
elgazst hasznlunk:
using System;
public class Program
{
static public void Main()
{
int x = 10;
if(x == 10) // Ha x egyenl 10 -zel
{
Console.WriteLine("x rtke 10");
}
}
}
Termszetes az igny arra is, hogy azt a helyzetet is kezelni tudjuk, amikor x rtke
nem tz. Ilyenkor hasznljuk az else gat:
using System;
public class Program
{
static public void Main()
{
int x = 11;
if(x == 10) // Ha x egyenl 10 -zel
{
Console.WriteLine("x rtke 10");
}
else // Ha pedig nem
{
Console.WriteLine("x rtke nem 10");
}
}
}
- 42 -
Ez a program pontosan ugyanazt csinlja, mint az elz, de van egy nagy klnbsg
a kett kztt: mindkt felttelt ki kell rtkelnie a programnak, hiszen kt klnbz
szerkezetrl beszlnk (ez egyttal azzal is jr, hogy a feltteltl fggen mindkt
llts lehet igaz).
Arra is van lehetsgnk, hogy tbb felttelt is megvizsgljunk, ekkor else-if et
hasznlunk:
using System;
public class Program
{
static public void Main()
{
int x = 13;
if(x == 10) // Ha x == 10 -zel
{
Console.WriteLine("x rtke 10");
}
elseif(x == 12) // Vagy 12 -vel
{
Console.WriteLine("x rtke 12");
}
else // De ha egyik sem
{
Console.WriteLine("x rtke nem 10 vagy 12");
}
}
}
A program az els olyan gat fogja vgrehajtani, amelynek a felttele teljesl (vagy
ha egyik felttel sem bizonyult igaznak, akkor az else gat ha adtunk meg ilyet).
- 43 -
Egy elgazsban pontosan egy darab if, brmennyi else-if s pontosan egy else g
lehet. Egy elgazson bell is rhatunk elgazst.
Az utols pldban olyan vltozt vizsgltunk, amely nagyon sokfle rtket vehet
fel. Nylvn ilyenkor nem tudunk minden egyes llapothoz felttelt rni (pontosabban
tudunk, csak az nem lesz szp). Ilyen esetekben azonban van egy egyszerbb s
elegnsabb megolds, mgpedig a switch-case szerkezet. Ezt akkor hasznljuk, ha
egy vltoz tbb lehetsges llapott akarjuk vizsglni:
using System;
public class Program
{
static public void Main()
{
int x = 11;
switch(x)
{
case 10:
Console.WriteLine("x rtke 10");
break;
case 11:
Console.WriteLine("x rtke 11");
break;
}
}
}
switch(animal)
{
case Animal.TIGER:
Console.WriteLine("Tigris");
break;
default:
Console.WriteLine("Nem ismerem ezt az llatot!");
break;
}
A C++ nyelvtl eltren a C# nem engedlyezi, hogy break utasts hinyban egyik
llapotbl tcssszunk egy msikba. Ez all a szably all egyetlen kivtel, ha az
adott g nem tartalmaz semmilyen utastst:
using System;
public class Program
{
enum Animal { TIGER, WOLF, CAT, DOG };
static public void Main()
{
Animal animal = Animal.DOG;
switch(animal)
{
case Animal.TIGER:
case Animal.DOG:
default:
Console.WriteLine("Ez egy llat!");
break;
}
}
A break utastson kvl hasznlhatjuk a goto t is, ekkor tugrunk a megadott gra:
using System;
public class Program
{
enum Animal { TIGER, WOLF, CAT, DOG};
static public void Main()
{
Animal animal = Animal.DOG;
switch(animal)
{
case Animal.TIGER:
goto default;
case Animal.DOG:
goto default;
default:
Console.WriteLine("Ez egy llat!");
break;
}
6.3 Ciklus
Amikor egy adott utastssorozatot egyms utn tbbszr kell vgrehajtanunk, akkor
ciklust hasznlunk. A C# ngyfle ciklust biztost szmunkra.
Az els az n. szmlls ciklus (nevezzk for-ciklusnak). Nzzk a kvetkez
programot:
- 45 -
using System;
public class Program
{
static public void Main()
{
for(int i = 0;i < 10;++i)
{
Console.WriteLine(i);
}
}
}
Vajon mit r ki a program? Mieltt ezt megmondanm, elszr inkbb nzzk meg
azt, hogy mit csinl: a for utni zrjelben talljuk az n. ciklusfelttelt, ez minden
ciklus rsze lesz, s azt adjuk meg benne, hogy hnyszor fusson le a ciklus. A
szmlls ciklus felttele els rnzsre elgg sszetett, de ez ne tvesszen meg
minket, valjban nem az. Mindssze hrom krdsre kell vlaszt adnunk: Honnan?
Meddig? s Hogyan?
Menjnk sorjban: a honnanra adott vlaszban megmondjuk azt, hogy milyen tpust
hasznlunk a szmolshoz s azt, hogy honnan kezdjk a szmolst.
Tulajdonkppen ebben a lpsben adjuk meg az n. Ciklusvltozt, amelyre a
ciklusfelttel pl. A fenti pldban egy int tpus ciklusvltozt hoztunk ltre a
ciklusfelttelen bell s nulla kezdrtket adtunk neki.
A ciklusvltoz neve konvenci szerint i lesz az angol iterate ismtel szbl. Tbb
ciklusvltoz hasznlatakor ltalban i, j, k ... sorrendet kvetnk.
Mivel a ciklusfelttel utn blokkot nyitunk, azt hinn az ember, hogy a ciklusvltoz a
loklis lesz a ciklus blokkjra (a for utn kvetkez kapcsos zrjelekkel hatrolt
rszre) nzve, de ez nem fedi a valsgot. A ciklusfelttelen bell deklarlt
ciklusvltoz loklis lesz a ciklust tartalmaz blokkra (vagyis ebben az esetben a
teljes Main fggvnyre) nzve. pp ezrt a kvetkez forrskd nem fordulna le:
using System;
public class Program
{
static public void Main()
{
for(int i = 0;i < 10;++i)
{
Console.WriteLine(i);
}
int i = 10; // itt a hiba
}
- 46 -
- 47 -
using System;
public class Program
{
static public void Main()
{
for(;;)
{
Console.WriteLine("Vgtelen ciklus");
}
}
}
- 48 -
using System;
public class Program
{
static public void Main()
{
int i = 0;
do
{
Console.WriteLine("i rtke: {0}", i);
++i;
}while(i < 10);
}
}
Vgl de nem utolssorban a foreach (neki nincs kln neve) ciklus kvetkezik.
Ezzel a ciklussal vgigiterlhatunk egy tmbn vagy gyjtemnyen, illetve minden
olyan objektumon, ami megvalstja az IEnumerable s IEnumerator interfszeket
(interfszekrl egy ksbbi fejezet fog beszmolni, ott lesz sz errl a kettrl is).
A pldnk most nem a mr megszokott szmoljunk el kilencig lesz, helyette
vgigmegynk egy stringen:
using System;
public class Program
{
static public void Main()
{
string str = "abcdefghijklmnopqrstuvwxyz";
foreach(char ch in str)
{
Console.Write(ch);
}
}
A ciklusfejben felvesznk egy char tpus vltozt (egy string karakterekbl ll),
utna az in kulcssz kvetkezik, amivel kijelljk, hogy min megynk t. A pldban
hasznlt ch vltoz nem ciklusvltoz, hanem n. itercis vltoz, amely felveszi az
iterlt gyjtemny aktulis elemnek rtkt. ppen ezrt egy foreach ciklus nem
mdosthatja egy gyjtemny elemeit (le sem fordulna ebben az esetben a program).
A foreach ciklus ktfle mdban kpes mkdni: ha a lista, amin alkalmazzuk,
megvalstja az IEnumerable s IEnumerator interfszeket, akkor azokat fogja
hasznlni, de ha nem, akkor hasonl lesz a vgeredmny, mint egy szmlls ciklus
esetben (leszmtva az itercis vltozt, az mindenkppen megmarad).
A foreach pontos mkdsvel az interfszekrl szl fejezet foglalkozik majd, ahol
tbbek kztt megvalstunk egy osztlyt, amelyen a foreach kpes vgigiterlni
(azaz megvalstjuk az IEnumerable s IEnumerator interfszeket).
- 49 -
6.3.1 Yield
A yield kifejezs lehetv teszi, hogy egy ciklusbl olyan osztlyt generljon a fordt,
amely megvalstja az IEnumerable interfszt s ezltal hasznlhat legyen pl. a
foreach ciklussal:
using System;
using System.Collections;
public class Program
{
static public IEnumerable EnumerableMethod(int max)
{
for(int i = 0;i < max;++i)
{
yield return i;
}
}
static public void Main()
{
foreach(int i in EnumerableMethod(10))
{
Console.Write(i);
}
}
}
- 50 -
using System;
using System.Collections.Generic;
using System.Threading.Tasks; // ez kell
class Program
{
static public void Main()
{
List<int> list = new List<int>()
{
1, 2, 4, 56, 78, 3, 67
};
Parallel.For(0, list.Count, (index) =>
{
Console.Write("{0}, ", list[index]);
});
Console.WriteLine();
Parallel.ForEach(list, (item) => Console.Write("{0}, ", item));
}
- 51 -
Gyakorl feladatok
7.1 Szorztbla
Ksztsnk szorztblt! A program vagy a parancssori paramterknt kapott szmot
hasznlja, vagy ha ilyet nem adtunk meg, akkor generljon egy vletlen szmot.
Megolds (7/Mtable.cs)
Elsknt ksztsk el a program vzt:
using System;
class Program
{
static public void Main(string[] args)
{
}
}
Vegyk szre, hogy a Main metdus kapott egy paramtert, mgpedig egy string
tpus elemekbl ll tmbt (tmbkrl a kvetkez fejezetek adnak tbb
tjkoztatst, most ez nem annyira lesz fontos). Ebben a tmbben lesznek az n.
parancssori paramtereink.
De mi is az a parancssori paramter? Egy nagyon egyszer pldt nzznk meg,
azt, amikor lefordtunk egy C# forrskdot:
csc main.cs
Ebben az esetben a csc a fordtprogram neve, mg a forrskdot tartalmaz file
neve pedig a paramter. Ha ezt vesszk alapul, akkor az args tmb egyetlen elemet
tartalmaz a csc-re nzve, mgpedig a main.cs t. Lssuk, hogy hogyan fog ez
kinzni a mi programunkban (feltesszk, hogy mul.exe lesz a neve):
mul.exe 12
Vagyis a 12 es szorztblt szeretnnk ltni.
A kvetkez lpsben fejlesszk tovbb a programot, hogy rja ki a paramterknt
megadott szm ktszerest. Ehhez mg szksgnk van arra is, hogy szm tpuss
alaktsuk a paramtert, hiszen azt stringknt kapjuk meg. Erre a feladatra az
int.Parse metdust hasznljuk majd, amely szmm konvertlja a paramtereknt
kapott szveget (persze csak akkor, ha ez lehetsges, egybknt kivtelt dob).
- 52 -
Egy kicsit szebb lesz a forrskd, ha az else g hasznlata helyett az if gba tesznk
egy return utastst, amely visszaadja a vezrlst annak a rendszernek amely az t
tartalmaz metdust hvta (ez a metdus jelen esetben a Main, t pedig mi vagyis
inkbb az opercis rendszer hvta, azaz a program befejezi a futst):
- 53 -
using System;
class Program
{
static public void Main(string[] args)
{
if(args.Length == 0)
{
Console.WriteLine("Adj meg egy paramtert!");
return;
}
int number = int.Parse(args[0]);
Console.WriteLine(number * 2);
}
== 0)
= new Random();
r.Next(100);
int.Parse(args[0]);
Console.WriteLine(number * 2);
}
}
- 54 -
using System;
class Program
{
static public void Main(string[] args)
{
int number;
if(args.Length == 0)
{
Randomr = new Random();
number = r.Next(100);
}
else
{
number = int.Parse(args[0]);
}
for(int i = 1;i <= 10;++i)
{
Console.WriteLine("{0} x {1} = {2}",
i, number, i * number);
}
}
7.2 Szmolgp
Ksztsnk egy egyszer szmolgpet! A program indtsakor krjen be kt szmot
s egy mveleti jelet, majd rja ki az eredmnyt.
Ezutn bvtsk ki a programot, hogy a kt szmot illetve a mveleti jelet parancssori
paramterknt is megadhassuk (ekkor nincs kln mveletvlaszt men, hanem
rjuk ki rgtn az eredmnyt):
main.exe 12 23 +
(az eredmny pedig 35 lesz).
Megolds (7/Calculator.cs)
Most is kt rszbl ll a programunk, elszr hozz kell jutnunk a szmokhoz s az
opertorhoz, majd elvgezzk a megfelel mveletet s kirjuk az eredmnyt.
Ezttal is a szksges vltozk deklarcijval kezdjk a programrst, hrom darab
kell, kt numerikus (legyen most int) s egy karaktertpus. Ezutn bekrjk a
felhasznltl a szksges adatokat, vagy pedig felhasznljuk a paramtereket. Ez
utbbi esetben vgezznk egy kis hibaellenrzst, vizsgljuk meg, hogy pontosan
hrom paramtert kaptunke!
- 55 -
- 56 -
int result=0;
switch(op)
{
case '+':
result
break;
case '-':
result
break;
case '*':
result
break;
case '/':
result
break;
}
= x + y;
= x - y;
= x * y;
= x / y;
Amire figyelni kell az az, hogy a result vltoz kapjon kezdrtket, ellenkez
esetben ugyanis nem fordul le a program (uninitialized variable kezdet hibazenetet
kapunk). Ez azrt van gy, mert a vltoz-deklarci s az utols sorban lev kirats
kztt nem biztos, hogy megtrtnik a vltoz-definci.
Ugyan az rtktpusok bizonyos helyzetekben automatikusan nulla rtket kapnak,
de ez nem minden esetben igaz s loklis vltozk esetn pp ez a helyzet. Ezrt
minden olyan esetben, amikor egy loklis vltoz deklarcija s defincija kztt
hasznlni akarjuk a vltozt, akkor hibazenetet fogunk kapni.
A fenti esetben megoldst jelenthet az is, ha bevezetnk a switch szerkezetben egy
default cmkt, amivel minden esetben megtrtnik - valamilyen formban az
rtkads.
- 57 -
- 58 -
- 59 -
switch(Console.ReadKey(true).KeyChar)
{
case 'i': goto START;
case 'n': break;
}
- 60 -
Kzben ki is egsztettk a kdot egy kicsit, lehet vele ksrletezni, amg el nem
ksztjk a lnyeget. Jl lthat, hogy a cmkkkel kellemesen olvashatv s
rthetv vlt a kd (persze ennl nagyobb terjedelm forrsnl mr problmsabb
lehet).
Mr elksztettk a programrszt, amely megkrdezi a jtkost, hogy szeretne-e mg
jtszani. Egy apr hibja van, mgpedig az, hogy ha i vagy n helyett ms billentyt
nyomunk le, akkor a program vgetr. Ezt knnyen kijavthatjuk, ha egy kicsit
gondolkodunk. Nylvn a default cmkt kell hasznlni s ott egy ugr utastssal a
vezrlst a megfelel helyre tenni:
END:
Console.WriteLine("\nAkarsz mg jtszani? i/n");
switch(Console.ReadKey(true).KeyChar)
{
case 'i': goto START;
case 'n': break;
default: goto END;
}
- 61 -
- 62 -
A min illetve max vltozkkal tartjuk szmon az intervallum als, illetve fels hatrt.
Az x vltozban troljuk az aktulis tippet, neki meg is adtuk a kezdrtket.
Egy pldn keresztl nzzk meg, hogy hogyan mkdik a kdunk. Legyen a
gondolt szm ismt 87. A szmtgp els tippje 50, mi erre azt mondjuk, hogy a
szm ennl nagyobb, ezrt a switch n ga fog beindulni. Az intervallum als hatra
ezutn x (vagyis 50) lesz, mivel tudjuk, hogy a szm ennl biztosan nagyobb. A fels
hatr nylvn nem vltozik, mr csak az j xet kell kiszmolni, vagyis xhez hozz
kell adni a fels s als hatrok klnbsgnek a felt: (100 50) / 2 = 25 (ellenkez
esetben pedig nylvn le kellene vonni ugyanezt).
Amirl mg nem beszltnk az az a felttel, amelyben x egyenlsgt vizsgljuk
hrommal (vagyis azt akarjuk tudni, hogy eljtt e az utols tipp ideje). Ez az
elgazs fogja visszaadni az utols tippet a vletlenszm-genertorral a megfelelen
leszktett intervallumban.
- 63 -
Tpuskonverzik
Ebben az esetben a long s int mindketten egsz numerikus tpusok, s mivel a long
tgabb (az int 32 bites mg a long 64 bites egsz szm), ezrt a konverzi gond
nlkl vgbe megy. Egy implicit konverzi minden esetben sikeres s nem jr
adatvesztssel.
Egy explicit konverzi nem felttlenl fog mkdni, s ha mgis akkor adatveszts is
fellphet. Vegyk a kvetkez pldt:
int x = 300;
byte y = (byte)x; // explicit konverzi, y == ??
A byte szkebb tpus mint az int (8 illetve 32 bitesek), ezrt explicit konverzit
hajtottunk vgre, ezt a vltoz eltti zrjelbe rt tpussal jelltk. Ha lehetsges a
konverzi, akkor vgbemegy, egybknt a fordt figyelmeztetni fog.
Vajon mennyi most az y vltoz rtke? A vlasz elsre meglep lehet: 44. A
magyarzat: a 300 egy kilenc biten felrhat szm (100101100), persze az int
kapacitsa ennl nagyobb, de most csak a hasznos rszre van szksg. A byte
viszont (ahogy a nevben is benne van) egy nyolcbites rtket trolhat (vagyis a
maximum rtke 255 lehet), ezrt a 300nak csak az els 8 bitjt (00101100)
adhatjuk t ynak, ami pont 44.
- 64 -
8.2 Is s as
Az is opertort futsidej tpus-lekrdezsre hasznljuk:
using System;
public class Program
{
static public void Main()
{
int x = 10;
terlete
az
interfsz-
- 65 -
8.3 Karakterkonverzik
A char tpust implicit mdon tudjuk numerikus tpusra konvertlni, ekkor a karakter
unicode rtkt kapjuk vissza:
using System;
class Program
{
static public void Main()
{
for(char ch = 'a';ch <= 'z';++ch)
{
Console.WriteLine((int)ch);
}
}
}
Erre a kimeneten a kvetkez szmok jelennek meg: 97, 98, 99, 100, ...
A kis a bet hexadecimlis unicode szma 0061h, ami a 97 decimlis szmnak felel
meg, teht a konverzi a tzes szmrendszerbeli rtket adja vissza.
- 66 -
Tmbk
Gyakran van szksgnk arra, hogy tbb azonos tpus objektumot troljunk el,
ilyenkor knyelmetlen lenne mindegyiknek kln vltozt foglalnunk (kpzeljnk el 30
darab int tpus vltozt, mg lerni is egy rkkvalsg lenne), de ezt nem is kell
megtennnk, hiszen rendelkezsnkre ll a tmb adatszerkezet.
A tmb meghatrozott szm, azonos tpus elemek halmaza. Minden elemre
egyrtelmen mutat egy index (egsz szm). A tmbk referencia-tpusok. A C#
mindig folytonos memriablokkokban helyezi el egy tmb elemeit.
Tmbt a kvetkezkppen deklarlhatunk:
int[] array = new int[10];
Ez a tmb tz darab int tpus elem trolsra alkalmas. A tmb deklarcija utn az
egyes indexeken lv elemek automatikusan a megfelel nullrtkre inicializldnak
(ebben az esetben 10 darab nullt fog tartalmazni a tmbnk). Ez a szably
referencia-tpusoknl kiss mshogy mkdik, mivel ekkor a tmbelemek null -ra
inicializldnak. Ez nagy klnbsg, mivel rtktpusok esetben szimpla nullt
kapnnk vissza az ltalunk nem belltott indexre hivatkozva (vagyis ez egy teljesen
szablyos mvelet), mg referencia-tpusoknl ugyanez NullReferenceException
tpus kivtelt fog generlni.
Az egyes elemekre az indexel opertorral (szgletes zrjelek: [ ]) s az elem
indexvel (sorszmval) hivatkozunk. A szmozs mindig nulltl kezddik, gy a
legutols elem indexe: az elemek szma mnusz egy. A kvetkez pldban
feltltnk egy tmbt vletlen szmokkal s kiratjuk a tartalmt:
using System;
class Program
{
static public void Main()
{
int[] array = new int[10];
Random r = new Random();
for(int i = 0;i < array.Length;++i)
{
array[i] = r.Next();
}
Ez itt egy 3x3as mtrix, olyan mint a fent lthat. Itt is sszekthetjk az elemek
megadst a deklarcival, br egy kicsit trkksebb a dolog:
int[,] matrix = new int[,]
{
{12, 23, 2},
{13, 67, 52},
{45, 55, 1}
};
- 68 -
Nylvn nem akarjuk mindig kzzel feltlteni a tmbket, viszont ezttal nem olyan
egyszer a dolgunk, hiszen egy ciklus biztosan nem lesz elg ehhez, vagyis
gondolkodnunk kell: az index els tagja a sort, a msodik az oszlopot adja meg,
pontosabban az adott sorban elfoglalt indext. Ez alapjn pedig j tletnek tnik, ha
egyszerre csak egy dologgal foglalkozunk, azaz szpen vgig kell valahogyan
mennnk minden soron egyesvel. Erre a megoldst az n. egymsba gyazott
ciklusok jelentik: a kls ciklus a sorokon megy t, a bels pedig a sorok elemein:
using System;
class Program
{
static public void Main()
{
int[,] matrix = new int[3, 3];
Random r = new Random();
// sorok
for(int i = 0;i < matrix.GetLength(0);++i)
{
// oszlopok
for(int j = 0;j < matrix.GetLength(1);++j)
{
matrix[i, j] = r.Next();
}
}
}
Ksztettnk egy hrom sorral rendelkez tmbt, azonban a sorok hosszt (az
egyes sorok nylvn nll vektorok) rrnk ksbb megadni, s nem kell
ugyanolyan hossznak lennik.
- 69 -
using System;
class Program
{
static public void Main()
{
int[][] jarray = new int[3][];
Random r = new Random();
for(int i = 0;i < 3;++i)
{
jarray[i] = new int[r.Next(1, 5)];
for(int j = 0;j < jarray[i].Length;++j)
{
jarray[i][j] = i + j;
}
}
}
- 70 -
10
Stringek
Ekkor a visszaadott objektum tpusa char lesz. A foreach ciklussal indexel opertor
nlkl is vgigiterlhatunk a karaktersorozaton:
foreach(char ch in s)
{
Console.WriteLine(ch);
}
10.1 Metdusok
A .NET szmos hasznos metdust biztost a stringek hatkony kezelshez. Most
megvizsglunk nhnyat, de tudni kell, hogy a metdusoknak szmos vltozata
lehet, itt most a leggyakrabban hasznltakat nzzk meg:
sszehasonlts:
using System;
class Program
{
static public void Main()
{
string a = "egyik";
string b = "msik";
int x = String.Compare(a, b);
if(x == 0)
{
Console.WriteLine("A kt string egyenl");
}
else if(x < 0)
{
Console.WriteLine("Az 'a' a kisebb");
}
else
{
Console.WriteLine("A 'b' a kisebb");
}
}
- 72 -
Az IndexOf s LastIndexOf metdusok egy string vagy karakter els illetve utols
elfordulsi indext (stringek esetn a kezdindexet) adjk vissza. Ha nincs tallat,
akkor a visszaadott rtk -1 lesz. A kt metdus Anyre vgzd vltozata egy
karaktertmbt fogad paramtereknt s az abban tallhat sszes karaktert
prblja megtallni. A Contains igaz rtkkel tr vissza, ha a paramtereknt
megadott karakter(sorozat) benne van a stringben.
Mdosts:
using System;
class Program
{
static public void Main()
{
string s = "smallstring";
char[] chs = new char[]{ 's', 'g' };
Console.WriteLine(s.Replace('s', 'l')); // lmallltring
Console.WriteLine(s.Trim(chs)); // mallstrin
Console.WriteLine(s.Insert(0, "one")); // onesmallstring
Console.WriteLine(s.Remove(0, 2)); // allstring
Console.WriteLine(s.Substring(0, 3)); // sma
Console.WriteLine(s.ToUpper()); // SMALLSTRING
Console.WriteLine(s.ToLower()); // smallstring
}
}
10.2 StringBuilder
Azt mr tudjuk, hogy amikor mdostunk egy stringet, akkor automatikusan egy j
pldny jn ltre a memriban, ez pedig nem felttlenl olcs mvelet.
Ha sokszor (legalbb 10+) van szksgnk erre, akkor hasznljuk inkbb a
StringBuilder tpust, ez automatikusan lefoglal egy nagyobb darab memrit, s ha
ez sem elg, akkor allokl egy megfelel mret terletet s tmsolja magt oda. A
StringBuilder a System.Text nvtrben tallhat.
- 73 -
A StringBuilder fenti konstruktora (van tbb is) helyet foglal tven karakter szmra
(ltezik alaprtelmezett konstruktora is, ekkor tizenhat karakternek foglal helyet). Az
Append metdussal tudunk karaktereket (vagy egsz stringeket) hozzfzni.
- 74 -
A regulris kifejezst egy Regex pldnynak adjuk t, lssuk, hogy hogyan pl fel:
^: ezzel a karakterrel (Alt Gr + 3) megmondjuk, hogy a mintaillesztst a string elejtl
kell kezdeni.
[1-9]: a string elejn egy darab numerikus karakter ll kivve a nullt.
[0-9]*: a csillag(*) nulla vagy tbb elfordulst jelent, vagyis az els szmjegy utn
nulla vagy tbb nulla s kilenc kztti szm llhat.
A programunk a kvetkez kimenetet produklja:
012345 : nem termszetes szm
112345 : termszetes szm
2 : termszetes szm
A kvetkez pldnk egy kicsit bonyolultabb lesz a regulris kifejezs pedig mr-mr
ijeszt: kpzeljk el, hogy a vilgon uniformizljk a telefonszmokat, a kvetkez
mdon: minden szm az orszg elhvjval kezddik amelyet egy + jel elz meg,
az elhvszm kt vagy hrom szmjegybl ll, az els szm nem lehet nulla.
Ezutn egy szkz jn, amelyet a krzetszm kvet, ami szintn kt vagy hrom
szmjegy az els helyen itt sem llhat nulla. Vgl kvetkezik a telefonszm, ami a
krzetszmot szkzzel elvlasztva kveti. Minden telefonszm hrom darab hrom
szmjegybl ll blokkbl ll ezeket ktjel vlasztja el. Egy plda:
+36 30 123-456-789
Lssuk a forrskdot:
string s = @"^(\+)[1-9][0-9]{1,2}\s[1-9][0-9]{1,2}\s(\d{3}(-)){2}\d{3}$";
Regex pattern = new Regex(s);
string s1 = "+36 30 661-345-612";
string s2 = "+3630 661-567-233";
string s3 = "+56 30 667-876-987-456";
Console.WriteLine(pattern.IsMatch(s1)); // true
Console.WriteLine(pattern.IsMatch(s2)); // false
Console.WriteLine(pattern.IsMatch(s3)); // false
karaktersor elejtl kezdjk, az ezt kvet (\+) pedig megmondja, hogy az els
helyen egy + jel van (ez persze nem lesz ott a krzetszm eltt). A + el \ t kell
tennnk, mivel ennek a jelnek nll jelentse is van regulris kifejezsben. A
zrjelek kz nyers karaktereket (is) rhatunk. Ezutn ismers kvetkezik: az [19][0-9] et mr nem okozhat gondot megrteni az utna kvetkez {1,2} t mr
inkbb. Ezzel azt kzltk, hogy az eltte lv meghatrozs ([0-9]) legalbb egy
legfeljebb kt alkalommal szerepel egyms utn. Vgl a \s egy szkzt jell.
(\d{3}(-)){2}\d{3}$: ez a kifejezs a ktjellel elvlasztott szmblokkokat jelli. A
vgn lv $ jel jelzi, hogy a karaktersorozat vgig kell illesztenie, vagyis az
egszet ellenrizze (msklnben a 345-345-345-456 sorozat rvnyes lenne,
hiszen benne van az amit kerestnk).
Haladjunk tovbbra is a vgrl a {3}rl mr tudjuk, hogy azt jelenti: az eltte lv
kifejezsnek pontosan hromszor kell szerepelnie, ez jelen esetben azt jelenti, hogy
a minta vgn hrom szmjegy ll, amelyet a \dvel (d mint digit) jellnk.
A \d eltt szerepl {2} az egsz zrjelben lv kifejezsre vonatkozik, ahol
megmondtuk, hogy hrom szmjegy utn egy ktjel kvetkezik.
A .NET regulris kifejezsei meglepen sokrtek, rengeteg lehetsgnk van, a
fenti kt plda csak zelt volt. Tovbbi informcit tallhatunk az MSDN megfelel
oldaln:
http://msdn.microsoft.com/en-us/library/az24scfc(v=VS.90).aspx
- 76 -
11
min = 1000;
max = -1;
minIdx = 0;
maxIdx = 0;
11.2 Szigetek
Egy szigetcsoport fltt elreplve bizonyos idkznknt megnztk, hogy pp hol
vagyunk. Ha sziget (szrazfld) fltt, akkor lertunk egy egyest, ha tenger fltt,
akkor nullt.
A programunk ezt az adatot dolgozza fl, amelyet vagy a billentyzetrl vagy ha
van a parancssori paramterbl kap meg. A feladatok:
- 77 -
A kdban kt rdekes dolog is van, az els a bels ciklus felttele: ellenrizzk, hogy
mg a szigetet mrjk s azt is, hogy nem-e rtnk a string vgre. Ami fontos, az a
felttelek sorrendje: mivel tudjuk, hogy a felttelek kirtkelse balrl jobbra halad,
ezrt elszr azt kell vizsglnunk, hogy helyes indexet hasznlunk-e, ellenkez
esetben ugyanis kivtelt kapnnk (hiszen ha a string vge utn vagyunk ott mr
nincs semmi).
A msik rdekessg a kt ciklusvltoz. Amikor befejezzk a bels ciklust, akkor a
kls ciklusvltozt j pozciba kell helyeznnk, mghozz oda, ahol a bels ciklus
abbahagyta a vizsglatot.
- 78 -
11.3 tlaghmrsklet
Az v minden napjn megmrtk az tlaghmrskletet, az eredmnyeket pedig egy
mtrixban troltuk (az egyszersg kedvrt tegyk fel, hogy minden hnap harminc
napos, az eredmnyeket pedig vletlenszm-genertorral (sszer kereteken bell)
sorsoljuk ki).
Keressk meg az v legmelegebb s leghidegebb napjt!
Adjuk meg az v legmelegebb s leghidegebb hnapjt!
Volt e egymst kvet t nap (egy hnapon bell), amikor mnusz fokot
mrtnk?
Megolds (11/Temperature.cs)
11.4 Buborkrendezs
Valstsuk meg egy tmbn a buborkrendezst.
Megolds (11/BubbleSort.cs)
A buborkos rendezs egy alapvet rendezsi algoritmus, amelynek alapelve, hogy
a kisebb elemek bubork mdjra felszivrognak, mg a nagyobb elemek
lesllyednek. Ennek az algoritmusnak tbbfle implementcija is ltezik, mi most
kt vltozatt is megvizsgljuk. Az els gy nz ki:
for(int i = 0;i < array.Length - 1;++i)
{
for(int j = array.Length - 1;j > i;--j)
{
if(array[j - 1] > array[j])
{
int tmp = array[j];
array[j] = array[j - 1];
array[j - 1] = tmp;
}
}
}
10 34 5
Fogjuk az 5 t (array[j]) s sszehasonltjuk az eltte lev elemmel, ami a 34
(array[j-1]). Mivel nagyobb nla, ezrt megcserljk a kettt:
10 5 34
Ezutn cskkentjk a ciklusvltozt, ami most megint az eddigi legkisebb elemre az
5 re fog mutatni s cserlhetjk tovbb. Termszetesen, ha kisebb elemet tallunk,
akkor ezutn t fogjuk tovbb vinni, egszen addig, amg a legkisebb elem elfoglalja
a tmb els indext. Itt jn kpbe a kls ciklus, ami azt biztostja, hogy a rendezett
elemeket mr ne vizsgljuk, hiszen a bels ciklus minden futsakor a tmb elejre
tesszk az aktulis legkisebb elemet.
Nzznk meg egy msik megoldst is:
for(int i = 1;i < array.Length;++i)
{
int y = array[i];
int j = i - 1;
while(j > -1 && y < array[j])
{
array[j + 1] = array[j];
--j;
}
array[j + 1] = y;
}
Itt lnyegben ugyanarrl van sz, csak most ellrl vizsgljuk az elemeket.
Nem rt tudni, hogy a buborkos rendezs csak kis elemszm esetben hatkony,
nagyjbl O(n^2) nagysgrend.
Az O() (n. nagy ord) jellst hasznljuk egy algoritmus futsidejnek
megbecslsre (illetve hasznljk a matematika ms terletein is).
- 80 -
12
12.1 UML
Az OOP tervezs elsegtsre hoztk ltre az UML t (Unified Modelling
Language). Ez egy ltalnos tervezeszkz, a clja, hogy egy minden fejleszt ltal
ismert kzs jelrendszert valstson meg. A kvetkezkben az UML eszkzeit fogjuk
felhasznlni az adatok kztti relcik grafikus brzolshoz.
12.2 Osztly
Az OOP vilgban egy osztly olyan adatok s mveletek sszessge, amellyel
lerhatjuk egy modell (vagy entits) tulajdonsgait s mkdst. Legyen pldul a
modellnk a kutya llatfaj. Egy kutynak vannak tulajdonsgai (pl. letkor, sly, stb.)
s van meghatrozott viselkedse (pl. csvlja a farkt, jtszik, stb.)
Az UML a kvetkezkppen jell egy osztlyt:
Kutya
Amikor programot runk, akkor az adott osztlybl (osztlyokbl) ltre kell hoznunk
egy (vagy tbb) pldnyt, ezt pdnyostsnak nevezzk. Az osztly s pldny
kztti klnbsgre j plda a recept (osztly) s a stemny (pldny).
- 81 -
12.4 Lthatsg
Az egyes tulajdonsgokat s metdusokat nem felttlenl kell kzszemlre
bocstani. Az OOP egyik alapelve, hogy a felhasznl csak annyi adatot kapjon
meg, amennyi felttlenl szksges. A kutys pldban az eszik() mvelet magba
foglalja a rgst, nyelst, emsztst is, de errl nem fontos tudniuk, csak az evs
tnye szmt.
Ugyangy egy tulajdonsg (adattag) esetben sem j, ha mindenki hozzjuk fr (az
elfogadhat, ha a kzvetlen csald hozzfr a szmlmhoz, de idegenekkel nem
akarom megosztani).
Az s-OOP szablyai hromfle lthatsgot fogalmaznak meg (ez nyelvtl fggen
bvlhet), a C# lthatsgairl a kvetkez rszekben lesz sz.
A hromfle lthatsg:
Public: mindenki lthatja (UML jells: +).
Private: csakis az osztlyon bell elrhet, a leszrmazott osztlyok nem
lthatjk s nem is mdosthatjk (a szrmaztats s rklds hamarosan
jn) (UML jells: -).
Protected: ugyanaz, mint a private, de a leszrmazott osztlyok
mdosthatjk is (UML jells: #).
- 82 -
12.5 Egysgbezrs
A hagyomnyos, nem OO programnyelvek (pl. a C) az adatokat s a rajtuk
vgezhet mveleteket a program kln rszeiknt kezelik. Bevett szoks ezeket
elklnteni egy nll forrsfileba, de ez mg mindig nem elg biztonsgos. A kett
kztt nincs sszerendels, ezrt ms programozk gond nlkl trhatjk egyiket
vagy msikat, illetve hozzfrnek a struktrkhoz s nem megfelelen hasznlhatjk
fel azokat.
Az OO paradigma egysgbe zrja az adatokat s a hozzjuk tartoz felletet, ez az
n. egysgbezrs (encapsulation vagy information hiding). Ennek egyik nagy
elnye, hogy egy adott osztly bels szerkezett gond nlkl megvltoztathatjuk,
mindssze arra kell figyelni, hogy a fellet ne vltozzon (pl. egy autt biztosan tudunk
kormnyozni, attl fggetlenl, hogy az egy szemlyaut, traktor vagy Forma-1es
gp).
12.6 rklds
Az rklds vagy szrmaztats az j osztlyok ltrehozsnak egy mdja. Egy
(vagy tbb) mr ltez osztlybl hozunk ltre egy jat gy, hogy az minden
szljnek tulajdonsgt rkli vagy tfogalmazza azokat. A legegyszerbben egy
pldn keresztl rthet meg. Legyen egy llat osztlyunk. Ez egy elgg tg
fogalom, ezrt szkthetjk a krt, mondjuk a Gerinces llatokra. Ezen bell
megklnbztethetnk Emls t vagy Hll t. Az Emls osztly egy
leszrmazottja lehet a Kutya s gy tovbb. Az rkldst specializlsnak is
nevezik. A specializls sorn az osztlyok kztt n. az-egy (is-a) relci ll fenn.
gy amikor azt mondjuk, hogy a Kutya az egy llat akkor arra gondolunk, hogy a
Kutya egy specializltabb forma, amelynek megvan a sajt karakterisztikja, de
vgeredmnyben egy llat. Ennek a gondolatmenetnek a gyakorlati felhasznls
sorn lesz jelentsge.
- 83 -
A diagram a fenti pldt brzolja. UML-l az rkldst res nyllal jelljk, amely
a specializlt osztly fell mutat az ltalnosabbra. Az osztlyok kztt fennll
kapcsolatok sszessgt hierarchinak nevezzk.
Elfordul, hogy nem fontos szmunkra a bels szerkezet, csak a felletet szeretnnk
trkteni, hogy az osztlyunkat fel tudja hasznlni a programunk egy msik rsze
(ilyen pldul a mr emltett foreach ciklus). Ilyenkor nem egy igazi osztlyrl,
hanem egy interfszrl felletrl beszlnk, amelynek nincsenek adattagjai,
csakis a mveleteket deklarlja.
A C# rendelkezik nll interfszekkel, de ez nem minden programnyelvre igaz, ezrt
k egy hasonl szerkezetet, n. absztrakt osztlyokat hasznlnak. Ezekben
elfordulnak adattagok is, de leginkbb a fellet definilsra koncentrlnak. A C#
nyelvi szinten tmogat absztrakt osztlyokat is, a kett kztt ugyanis lnyegi
klnbsg van. Az interfszek az osztlytl fggetlenek, csakis felletet biztostanak
(pldul az IEnumerable s IEnumerator a foreachnek (is) biztostanak felletet, az
nem lnyeges, hogy milyen osztlyrl van sz). Az absztrakt osztlyok viszont egy
shz ktik az utdokat (erre az esetre plda az llat osztly, amelyben mondjuk
megadunk egy absztrakt evs metdust, amit az utdok megvalstanak - egy
krokodil nylvn mshogy eszik mint egy hangya, de az evs az llatokhoz kthet
valami, ezrt kzs).
- 84 -
13
Osztlyok
- 85 -
13.1 Konstruktorok
Minden esetben amikor pldnyostunk egy specilis metdus a konstruktor fut le,
melynek feladata, hogy belltsa az osztly rtkeit. Br a fenti osztlyunkban nem
definiltunk semmi ilyesmit ettl fggetlenl rendelkezik alaprtelmezett (azaz
paramter nlkli) konstruktorral. Ez igaz minden olyan osztlyra, amelynek nincs
konstruktora (amennyiben brmilyen konstruktort ltrehoztunk, akkor ez a lehetsg
megsznik).
Az alaprtelmezett konstruktor legelszr meghvja a sajt sosztlya
alaprtelmezett konstruktort. Ha nem szrmaztattunk direkt mdon (mint a fenti
programban), akkor ez a System.Object konstruktora lesz (tulajdonkppen ez elbb
vagy utbb mindenkppen meghvdik, hiszen az sosztly konstruktora is meghvja
a sajt st s gy tovbb).
Abban az esetben, ha az sosztly nem tartalmaz alaprtelmezett konstruktort (mert
van neki paramteres), akkor valamely msik konstruktort explicit mdon hvni kell a
leszrmazott osztly konstruktorbl a base metdussal, minden ms esetben
fordtsi hiba az eredmny.
class Base
{
public Base(string s){ }
}
class Derived : Base
{
}
- 86 -
class Base
{
public Base(string s){ }
}
class Derived : Base
{
public Derived() : base("abc"){ }
}
- 87 -
Ha tbb konstruktor is van, akkor a paramter tpushoz leginkbb illeszked fut le.
A pldban a konstruktor trzsben rtket adtunk a mezknek a this hivatkozssal,
amely mindig arra a pldnyra mutat, amelyen meghvtk (a this kifejezs gy minden
olyan helyen hasznlhat, ahol az osztlypldnyra van szksg). Nem ktelez
hasznlni, ugyanakkor hasznos lehet, hogy ha sok adattag/metdus van, illetve ha a
paramterek neve megegyezik az adattagokval. A fordtprogram automatikusan
odakpzeli magnak a fordts sorn, gy mindig tudja mivel dolgozik.
Az adattagok private elrsek (ld. elmleti rsz), azaz most csakis az osztlyon
bell hasznlhatjuk s mdosthatjuk ket, pldul a konstruktorban, ami viszont
publikus.
Nem csak a konstruktorban adhatunk rtket a mezknek, hanem hasznlhatunk n.
inicializlkat is:
class Dog
{
private string _name = "Rex";
private int _age = 5;
public Dog(string name, int age)
{
this._name = name;
this._age = age;
}
}
Az inicializls mindig a konstruktor eltt fut le, ez egyben azt is jelenti, hogy az
utbbi fellbrlhatja. Ha a Dog osztlynak ezt a mdostott vltozatt hasznltuk
volna fentebb, akkor a pldnyosts sorn minden esetben fellrnnk az
alaprtelmezettnek megadott kort.
Az inicializls sorrendje megegyezik a deklarls sorrendjvel (fellrl lefel halad).
A konstruktorok egy specilis vltozata az n. msol- vagy copy-konstruktor. Ez
paramtereknt egy sajt magval megegyez tpus objektumot kap s annak
rtkeivel inicializlja magt. Msol konstruktort ltalban az rtkad opertorral
szoktak implementlni, de az opertor-kiterjeszts egy msik fejezet tmja, gy most
egyszerbben oldjuk meg:
- 88 -
class Dog
{
private string _name = "Rex";
private int _age = 5;
public Dog(string name, int age)
{
this._name = name;
this._age = age;
}
public Dog(Dog otherDog)
: this(otherDog._name, otherDog._age)
{ }
}
A program els rnzsre furcsa lehet, mivel privt elrhetsg tagokat hasznlunk,
de ezt minden gond nlkl megtehetjk, mivel a C# a privt elrhetsget csak
osztlyon kvl rvnyesti, ugyanolyan tpus objektumok ltjk egymst.
Most mr hasznlhatjuk is az j konstruktort:
Dog d = new Dog("Rex", 2);
Dog e = new Dog(d);
13.2 Adattagok
Az adattagok vagy mezk olyan vltozk, amelyeket egy osztlyon (vagy struktrn)
bell deklarltunk. Az adattagok az osztlypldnyhoz tartoznak (azaz minden egyes
pldny klnll adattagokkal rendelkezik) vele szletnek s halnak is meg. Az
eddigi pldinkban is hasznltunk mr adattagokat, ilyenek voltak a Dog osztlyon
belli _name s _age vltozk.
Az adattagokon hasznlhatjuk a const tpusmdostt is, ekkor a deklarcinl
rtket kell adnunk a meznek, hasonlan az elz fejezetben emltett
inicializlshoz. Ezek a mezk pontosan ugyangy viselkednek mint a hagyomnyos
konstansok.
Egy konstans mezt nem lehet statikusnak (statikus tagokrl hamarosan) jellni,
mivel a fordt egybknt is gy fogja kezelni (ha egy adat minden objektumban
vltozatlan, felesleges minden alkalommal kln pldnyt kszteni belle), vagyis
minden konstans adattagbl globlisan minden pldnyra vonatkozan egy darab
van.
A mezkn alkalmazhat a readonly mdost is, ez kt dologban klnbzik a
konstansoktl: az rtkads elhalaszthat a konstruktorig s az rtkl adott
kifejezs eredmnynek nem szksges ismertnek lennie fordtsi idben.
- 89 -
- 90 -
Parcilis metdusnak nem lehet elrhetsgi mdostja (pp ezrt minden esetben
private elrs lesz) valamint void-dal kell visszatrnie.
A partial kulcsszt ilyenkor is ki kell tenni minden elfordulsnl. Csakis parcilis
osztly tartalmazhat parcilis metdust.
- 91 -
- 92 -
Ilyen esetekben vagy egy nyilvnos tagra, vagy egy tulajdonsgra hivatkozunk (ez
utbbit hasznltuk). Termszetesen, ha ltezik paramteres konstruktor, akkor is
hasznlhatjuk ezt a belltsi mdot.
13.7 Destruktorok
A destruktorok a konstruktorokhoz hasonl specilis metdusok, amelyek az osztly
ltal hasznlt erforrsok felszabadtsrt felelsek.
A .NET n. automatikus szemtgyjt (garbage collector) rendszert hasznl,
amelynek lnyege, hogy a hivatkozs nlkli objektumokat (nincs rjuk mutat
rvnyes referencia) a keretrendszer automatikusan felszabadtja.
MyClass mc = new MyClass(); // mc egy MyClass objektumra mutat
mc = null; // az objektumra mr nem mutat semmi, felszabadthat
using System;
class Program
{
static public void Main()
{
Console.WriteLine("Foglalt memria: {0}",
GC.GetTotalMemory(false));
for(int i = 0;i < 10;++i)
{
int[] x = new int[1000];
}
Console.WriteLine("Foglalt memria: {0}",
GC.GetTotalMemory(false));
GC.Collect(); // meghvjuk a szemtgyjtt
Console.WriteLine("Foglalt memria: {0}",
GC.GetTotalMemory(false));
}
}
- 94 -
- 96 -
Vagy:
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
A destruktor neve tilde jellel (~) kezddik, neve megegyezik az osztlyval, s nem
lehet semmilyen mdostja vagy paramtere (rtelemszeren egy destruktor mindig
privt elrhetsg lesz, vagyis kzvetlenl soha nem hvhatjuk, ez csakis a GC
eljoga).
Soha ne ksztsnk res destruktort, mivel a GC minden destruktorrl bejegyzst
kszt, s mindenkppen meghvja mindegyiket akkor is, ha res, vagyis ez egy
felesleges metdushvs lenne.
Ha lefordtjuk ezt a kdot s elindtjuk a programot, elszr a Konstruktor szt
fogjuk ltni, majd egy gomb lenyomsa utn megjeleni a prja is (ha ltni is akarjuk,
nem rt parancssorbl futtatni). A fenti kd valjban a kvetkez formban ltezik:
class DestructableClass
{
public DestructableClass()
{
Console.WriteLine("Konstruktor");
}
protected override void Finalize()
{
try
{
Console.WriteLine("Destruktor");
}
finally
{
base.Finalize();
}
}
}
- 98 -
Ez a forrskd csak plda, nem fordul le, mivel a Finalize metdust nem
definilhatjuk fell, erre val a destruktor.
A Finalize-t minden referencia-tpus rkli a System.Object tl. Elszr felszabadtja
az osztly erforrsait (a destruktorban ltalunk megszabott mdon), azutn
meghvja az sosztly Finalize metdust (ez legalbb a System.Object destruktora
lesz) s gy tovbb, amg a lnc vgre nem r:
using System;
class Base
{
~Base()
{
Console.WriteLine("Base");
}
}
class Derived : Base
{
~Derived()
{
Console.WriteLine("Derived");
}
}
class Program
{
static public void Main()
{
Derived d = new Derived();
}
}
- 99 -
13.7.1 IDisposable
Az IDisposable interfsz segtsgvel egy osztly ltal hasznlt erforrsok
felszabadtsa kzzel elre meghatrozott idpontban is megtrtnhet, teht
nem kell a GC re vrni.
using System;
class DisposableClass : IDisposable
{
public void Dispose()
{
// Takartunk
GC.SuppressFinalize(this);
}
}
class Program
{
static public void Main()
{
DisposableClass dc = new DisposableClass();
}
}
- 100 -
- 101 -
14
Metdusok
class Program
{
static public void Main()
{
Dog d = new Dog("Rex", 2);
d.Eat();
d.Sleep();
}
}
Nzzk meg, hogyan pl fel egy metdus: elsknt megadjuk a lthatsgot s itt is
rvnyes a szably, hogy ennek hinyban az alaprtelmezett privt elrs lesz
rvnyben. Ezutn a visszatrsi rtk tpusa ll, jelen esetben a voiddal jeleztk,
hogy nem vrunk ilyesmit. Kvetkezik a metdus neve, ez konvenci szerint
nagybetvel kezddik, vgl a sort a paramterlista zrja.
- 102 -
Egy metdust az objektum neve utn rt pont opertorral hvhatunk meg (ugyanez
rvnyes a publikus adattagokra, tulajdonsgokra, stb. is).
A hagyomnyos procedurlis programozs (pl. a C vagy Pascal nyelv) a
metdusokhoz hasonl, de filozfijban ms eszkzket hasznl, ezek a fggvny
(function) s az eljrs (procedure). Mi a klnbsg? Azt mondtuk, hogy a
metdusok egy osztlyhoz kthetek, annak letciklusban jtszanak szerepet.
Nzznk egy pldt:
using System;
class NewString1
{
private string aString;
public NewString1(string s)
{
this.aString = s;
}
public void PrintUpper()
{
Console.WriteLine(this.aString.ToUpper());
}
}
class NewString2
{
public void PrintUpper(string s)
{
Console.WriteLine(s.ToUpper());
}
}
class Program
{
static public void Main()
{
NewString1 ns1 = new NewString1("baba");
NewString2 ns2 = new NewString2();
ns1.PrintUpper();
ns2.PrintUpper("baba");
}
Pontosan ugyanaz trtnik mindkt esetben, de van egy nagy klnbsg. Az els
osztly valdi osztly: adattaggal, konstruktorral, stb. Van llapota, vgezhetnk
rajta mveleteket. A msodik osztly nem igazi osztly, csak egy doboz, amelyben
egy teljesen nll, egyedl is letkpes szerkezet van, mindssze azrt kell az
osztly-definci, mert egybknt nem fordulna le a program (ebben az esetben egy
statikus metdust kellett volna ksztennk, errl hamarosan).
Az els osztlyban metdust definiltunk, a msodikban eljrst (eljrs s fggvny
kztt a lnyegi klnbsg, hogy utbbinak van visszatrsi rtke).
- 103 -
14.1 Paramterek
Az objektummal val kommunikci rdekben kpesnek kell lennnk kvlrl
megadni adatokat, vagyis paramtereket. A paramterek szmt s tpusait a
metdus deklarcijban, vesszvel elvlasztva adjuk meg. Egy metdusnak
gyakorlatilag brmennyi paramtere lehet.
A metdus nevt s paramterlistjt alrsnak, szignatrnak vagy prototpusnak
nevezzk. Egy osztly brmennyi azonos nev metdust tartalmazhat, ameddig a
paramterlistjuk klnbzik. A paramterek a metduson bell loklis vltozkknt
viselkednek, s a paramter nevvel hivatkozunk rjuk.
using System;
class Test
{
public void Method(string param)
{
Console.WriteLine("A paramter: {0}", param);
}
}
class Program
{
static public void Main()
{
Test t = new Test();
t.Method("Paramter");
}
}
- 104 -
using System;
class Test
{
public int x = 10;
public void TestMethod(Test t)
{
t = new Test();
t.x = 11;
}
}
class Program
{
static public void Main()
{
Test t = new Test();
Console.WriteLine(t.x); // 10;
t.TestMethod(t);
Console.WriteLine(t.x); // 10
}
}
- 105 -
using System;
class Test
{
public void Swap(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
}
class Program
{
static public void Main()
{
int x = 10;
int y = 20;
Test t = new Test();
t.Swap(x, y);
Console.WriteLine("x = {0}, y = {1}", x, y);
}
- 106 -
A fenti programokban pontosan tudtuk, hogy hny paramtere van egy metdusnak.
Elfordul viszont, hogy ezt nem tudjuk egyrtelmen megmondani, ekkor n.
paramter-tmbket kell hasznlnunk. Ha ezt tesszk, akkor az adott metdus
paramter-listjban a paramter-tmbnek kell az utols helyen llnia, illetve egy
paramter-listban csak egyszer hasznlhat ez a szerkezet.
using System;
class Test
{
public void PrintElements(params object[] list)
{
foreach(var item in list)
{
Console.WriteLine(item);
}
}
}
class Program
{
static public void Main()
{
Test t = new Test();
t.PrintElements("alma", "krte", 4, 1, "di");
t.PrintElements(); // ez is mkdik
}
}
- 108 -
- 109 -
Personp1=newPerson("Istvn","Reiter");
Personp2=newPerson("Istvn","Reiter","brtnr");
Mivel tudatjuk a fordtval, hogy pontosan melyik paramterre gondolunk, ezrt nem
kell betartanunk az eredeti metdus-deklarciban elrt sorrendet:
Person p = new Person(lastName:"Reiter", firstName:"Istvn");
- 110 -
Ez a metdus nem fordul le, mivel nem lesz minden krlmnyek kztt visszatrsi
rtk. A visszatrtett rtk tpusnak vagy egyeznie kell a visszatrsi rtk
tpusval, vagy a kett kztt lteznie kell implicit tpuskonverzinak:
public int Add(int x, int y)
{
return (byte)(x + y); // ez mkdik, br nincs sok rtelme
}
public int Add(int x, int y)
{
return (long)(x + y);// ez le sem fordul
}
- 111 -
using System;
static public class StringHelper
{
static public void Print(this string s)
{
Console.WriteLine(s);
}
}
class Program
{
static public void Main()
{
string s = "ezegystring";
s.Print();
StringHelper.Print(s); // gy is hasznlhatjuk
}
}
- 112 -
15
Tulajdonsgok
string name;
public string Name
{
get { return this.name; }
set { this.name = value; }
}
class Program
{
static public void Main()
{
Person p = new Person("Istvn");
Console.WriteLine(p.Name);
}
}
Lthatjuk, hogy egy property deklarci hasonlan pl fel mint a metdusok, azzal
a kivtellel, hogy nincs paramterlista. Vegyk szre, hogy a setterben egy
ismeretlen, value nev vltozt hasznltunk. Ez egy specilis elem, azt az rtket
tartalmazza amelyet hozzrendeltnk a setter-hez:
Person p = new Person("Istvn");
p.Name = "Bla"; // value == "Bla"
- 113 -
Arra is van lehetsg, hogy csak az egyiket hasznljuk, ekkor csak rhat/olvashat
tulajdonsgokrl beszlnk:
public string Name
{
get { return this._name; }
}
A fordt automatikusan ltrehoz egy private elrs, string tpus name nev
adattagot s elkszti hozz a getter-t/setter-t is. Van azonban egy problma,
mghozz az, hogy a fordts pillanatban ez a vltoz mg nem ltezik, vagyis
kzvetlenl nem hivatkozhatunk r pl. a konstruktorban. Ilyenkor a setter-en keresztl
kell rtket adnunk.
class Person
{
public Person(string name)
{
this.Name = name;
}
public string Name
{
get; set;
}
}
- 114 -
16
Indexelk
}
class Program
{
static public void Main()
{
Names n = new Names();
for(int i = 0;i < n.Count;++i)
{
Console.WriteLine(n[i]);
}
}
- 115 -
- 116 -
17
Statikus tagok
- 117 -
- 118 -
- 120 -
{
return Math.Cos(x);
}
}
class Program
{
static public void Main()
{
Console.WriteLine(MathHelper.Cos(1));
}
}
- 121 -
18
Struktrk
18.1 Konstruktor
Minden struktra alaprtelmezetten rendelkezik egy konstruktor-szersggel
(vigyzat, nem igazi konstruktor), amely elvgzi a tagok nullra inicializlst
(lnyegben nullkkal tlti fel az adott memriaterletet). Ez a lehetsg mindig l,
nem rejthet el.
using System;
struct Test
{
public int x;
}
class Program
{
static public void Main()
{
Test t = new Test();
Console.WriteLine(t.x); // x == 0
}
}
- 122 -
rtkadsrl
structTest
{
int _x = 10; // ez nem j
int _y;
public Test(int x, int y)
{
_y = y;// ez sem j, x nem kap rtket
}
}
18.2 Destruktor
Struktrk nem rendelkezhetnek destruktorral. Egy struktra kt helyen lehet a
memriban: a stack-ben s a heap-ben (ha egy referencia-tpus tagja).
Ahhoz, hogy megrtsk, hogy mirt nincs destruktor, szksgnk van a kvetkezre:
egy struktrban lv referenciatpusnak csak a referencijt troljuk. Ha a
veremben van a struktra, akkor elbb vagy utbb kikerl onnan, s mivel gy a
benne lv referenciatpusra mr nem mutat referencia (legalbbis a struktrbl
nem) ezrt eltakarthat. Ugyanez a trtnet akkor is, ha a struktra pldny egy
referenciatpusban foglal helyet.
- 123 -
18.3 Adattagok
A struktrk az adattagokat kzvetlenl troljk (mg osztlyok esetben mindig
referencikat tartunk szmon). Egy struktra minden adattagja amennyiben a
konstruktorban nem adunk meg mst automatikusan a megfelel nulla rtkre
inicializldik.
Struktra nem tartalmazhat sajt magval megegyez tpus adattagot. Ugyangy,
egy struktra nem tartalmazhat olyan tpus tagot, amely tpus hivatkozik az eredeti
struktrra:
struct Test
{
Test t;
}
struct Test1
{
Test2 t;
}
struct Test2
{
Test1 t;
}
18.4 Hozzrendels
Amikor egy struktra pldnynak egy msik pldnyt adunk rtkl akkor egy
teljesen j objektum keletkezik:
using System;
struct Test
{
public int x;
}
class Program
{
static public void Main()
{
Test t1 = new Test();
Test t2 = t1;
t2.x = 10;
Console.WriteLine("t1.x = {0}, t2.x = {1}", t1.x, t2.x);
}
}
- 124 -
Ha lefordtjuk ezt a kdot, azt fogjuk ltni, hogy t1.x rtke nem vltozott, teht nem
referencit adtunk t t2nek.
Most nzznk meg egy nagyon gyakori hibt, amibe belefuthatunk. Adott a
kvetkez programkd:
using System;
struct Point
{
int _x;
public int X
{
get { return_x; }
set { _x = value; }
}
int _y;
public int Y
{
get { return_y; }
set { _y = value; }
}
public Point(int x, int y)
{
_x = x;
_y = y;
}
}
struct Line
{
Point a;
public Point A
{
get { return a; }
set { a = value; }
}
Point b;
public Point B
{
get { return b; }
set { b = value; }
}
}
class Program
{
static public void Main()
{
Line l = new Line();
l.A = new Point(10, 10);
l.B = new Point(20, 20);
}
}
Ez a forrskd nem fog lefordulni, mivel nem vltoznak akarunk rtket adni. Mi
lehet a hiba oka? A problma ott van, hogy rosszul rtelmeztk ezt a kifejezst. Az
l.A valjban a getter-t hvja meg, ami az eredeti struktra egy msolatval tr
vissza, amelynek a tagjait mdostani viszont nincs rtelme. Ilyen esetekben mindig
j struktrt kell ksztennk:
static public void Main()
{
Line l = new Line();
l.A = new Point(10, 10);
l.B = new Point(20, 20);
l.A = new Point(5, 10);
}
18.5 rklds
Struktrk szmra az rklds tiltott, minden struktra automatikusan sealed
mdostt kap. Ilyen mdon egy struktra nem lehet absztrakt, tagjainak
elrhetsge nem lehet protected/protected internal, metdusai nem lehetnek
virtulisak illetve csak a System.ValueType) metdusait definilhatja t. Ez utbbi
esetben a metdushvsok nem jrnak bedobozolssal:
using System;
class Test
{
public int x;
public override string ToString()
{
return "X == " + x.ToString();
}
}
class Program
{
static public void Main()
{
Test t = new Test();
t.x = 10;
Console.WriteLine(t.ToString());
}
}
- 126 -
19
Lthat, hogy xet (az alapot) rintetlenl hagyjuk, mg a kitevt (y) a fggvny
minden hvsakor eggyel cskkentjk, egszen addig, amg rtke nulla nem lesz,
ekkor befejezzk az rdgi krt s visszaadjuk az eredmnyt.
Hasonlkppen kszthetjk el a faktorilist szmol programot is:
using System;
class Program
{
static public int Fact(int x)
{
if(x == 0){ return 1; }
else return x * Fact(x - 1);
}
- 127 -
19.2 Gyorsrendezs
Valstsuk meg a gyorsrendezst!
Megolds (19/QuickSort.cs)
A gyorsrendezs a leggyorsabb rendez algoritmus, nagy elemszm esetn
O(n*logn) nagysgrend tlaggal. Az algoritmus lnyege, hogy a rendezend
elemek kzl kivlaszt egy n. pivot elemet, amely el a nla nagyobb, mg pedig a
nla kisebb elemeket teszi, majd az gy kapott kt csoportra ismt meghvja a
gyorsrendezst (teht egy rekurzv algoritmusrl beszlnk). Lssuk, hogy hogyan is
nz ez ki a gyakorlatban!
Nagy elemszmnl ugyan jl teljest ez az algoritmus, de kevs elem esetn fordul a
kocka. ppen ezrt amikor a rendezsre tadott tmbrszlet kellen kicsi akkor egy
ltalnosabb rendezst, pl. buborkrendezst rdemes hasznlni.
A legtbb programozsi nyelv beptett rendezsei ltalban a gyorsrendezs egy
varicijt hasznljk.
class Array
{
private int[] array;
public Array(int length)
{
array = new int[length];
}
public int this[int idx]
{
get { return array[idx]; }
set { array[idx] = value; }
}
public int Length
{
get { return array.Length; }
}
public void Sort()
{
QuickSort(0, array.Length - 1);
}
private void QuickSort(int left, int right)
{
// rendezs...
}
}
elgazs szintn kimarad s nekillhatunk kiszmolni, hogy miknt hvjuk meg jra a
metdust. A tmb vltozatlan marad, a pivot vltoz nulla rtket kap, right s left
pedig visszakapjk az eredeti rtkket.
Ezutn a msodik elgazst fogjuk hasznlni (ne feledjk, hogy right rtke ismt 5)
s meghvjuk a QuickSort metdust 1 illetve 5 paramterekkel, vagyis az els elemet
(3) mivel mr a helyn van tugorjuk.
Kvetkezik a msodik fordul, a pivot vltoz rtke most kilenc lesz, mg left s right
rtke 1 s 5. Az els ciklus egyszer fog lefutni hiszen a tmb negyedik indexn l
nyolcas szm mr kissebb mint a pivot elem. Left nem egyenl right tal ezrt a
kvetkez elgazsba is bemegynk s a left indexre helyezzk a right indexen lv
nyolcast (a pivot elem pedig pont az itt mr nem lv kilencest trolja). Left elrelp
eggyel, hogy a tmb msodik indexre (4) mutasson.
A msodik ciklus is lefut, egszen addig fogjuk nvelni left rtkt, amg elri a right
ltal mutatott nyolcast, hiszen ott a ciklus felttel msodik fele srl. Most left s right
rtke egyenl: 4. ppen ezrt a msodik elgazst kihagyjuk s tovbb lpnk. A
left ltal mutatott indexre behelyezzk a pivotban lv kilencest, amivel helyre is ll a
rend. Pivot rtke ezutn ngy lesz s a kt msik vltoz is visszakapja az rtkt.
Left kissebb most, mint a pivot s right pedig nagyobb nla gy mindkt elgazs
felttele teljesl, vagyis most mindkt oldalra hvjuk a metdust.
Az ez utni esemnyek tgondolsa pedig az olvas feladata.
- 130 -
A
B
Az osztly vza hasonlt a lncolt listhoz, itt is szksgnk van egy gykrelemre,
ez tulajdonkppen a legels beszrt cscs lesz.
- 132 -
- 133 -
10
12
- 134 -
- 135 -
20
rklds
- 136 -
Ha ezt az j Animal osztllyal prblnnk meg akkor meglepets fog rni, mivel nem
fordul le a program. Ahhoz, hogy ki tudjuk javtani a hibt tudnunk kell, hogy a
leszrmazott osztlyok elszr mindig a kzvetlen sosztly konstruktort hvjk
meg, vagyis ha nem adunk meg mst az alaprtelmezett konstruktort. A
problma az, hogy az sosztlynak mr nincs ilyenje, ezrt a leszrmazott
osztlyokban explicit mdon hvni kell a megfelel konstruktort:
class Animal
{
public Animal(string name)
{
this.Name = name;
}
public string Name { get; set; }
public void Eat()
{
Console.WriteLine("Hamm - Hamm");
}
}
class Dog : Animal
{
public Dog(string name) : base(name)
{
}
Ezutn gy pldnyostunk:
static public void Main()
{
Dog d = new Dog("Bunds");
Crocodile c = new Crocodile("Aladr");
Console.WriteLine("{0} s {1}", d.Name, c.Name);
}
- 137 -
Honnan tudja vajon a fordt, hogy egy sosztlybeli metdust kell meghvnia? A
referenciatpusok specilis mdon jelennek meg a memriban, rendelkeznek tbbek
kzt egy n. metdus-tblval, ami mutatja, hogy az egyes metdushvsoknl
melyik metdust kell meghvni. Persze ezt is meg kell hatrozni valahogy, ez nagy
vonalakban gy trtnik, hogy a fordt a fordts pillanatban megkapja a metdus
nevt s elindul visszafel az osztlyhierarchia mentn. A fenti pldban a hv
osztly nem rendelkezik Eat nev metdussal s nem is definilja t annak a
viselkedst (errl hamarosan), ezrt az eggyel feljebbi st kell megnznnk. Ez
egszen a lehet legjabb metdusdefinciig megy, s amikor megtallja a
megfelel implementcit, bejegyzi azt a metdustblba.
- 138 -
Ezutn a Dog utdjai mr nem ltjk az eredeti Eat metdust. Viszont kszthetnk
belle virtulis metdust, amelyet az utdai mr kedvkre hasznlhatnak. Azaz, a
new mdostval elltott metdus j sort kezd, amikor a fordt felpti a
metdustblt, vagyis a new virtual kulcsszavakkal elltott metdus lesz az j
metdussorozat gykere.
- 139 -
20.2 Polimorfizmus
Korbban mr beszltnk arrl, hogy az s s leszrmazottak kzt az-egy (is-a)
relci ll fent. Ez a gyakorlatban azt jelenti, hogy minden olyan helyen, ahol egy
stpust hasznlunk, ott hasznlhatunk leszrmazottat is (pl. egy llatkertben llatok
vannak, de az llatok helyre (nylvn) behelyettesthetek egy specilisabb fajt).
Pldul gond nlkl rhatom a kvetkezt:
Animal d = new Dog("Bunds");
A new opertor meghvsa utn d gy fog viselkedni, mint a Dog osztly egy
pldnya (elvgre az is lesz), hasznlhatja annak metdusait, adattagjait. Arra
azonban figyeljnk, hogy ez visszafel nem mkdik, a fordt hibt jelezne.
Abban az esetben ugyanis, ha a fordt engedn a visszafel konverzit az n.
leszeletelds (slicing) effektus lpne fel, azaz az adott objektum elveszten a
specilisabb osztlyra jellemz karakterisztikjt. A C++ nyelvben sokszor jelent
gondot ez a problma, mivel ott egy pointeren keresztl megtehet a lebutts.
Szerencsre a C# nyelvben ezt megoldottk, gy nem kell aggdnunk miatta.
Mi trtnik vajon a kvetkez esetben:
static public void Main()
{
Animal[] animalArray = new Animal[2];
animalArray[0] = new Animal();
animalArray[1] = new Dog();
animalArray[0].Eat();
animalArray[1].Eat();
}
Amit a fordt lt az az, hogy ksztettnk egy Animal tpus elemekbl ll tmbt
s, hogy az elemein meghvtuk az Eat metdust. Csakhogy az Eat egy virtulis
metdus, radsul van leszrmazottbeli implementcija is, amely tdefinlja az
eredeti viselkedst, s ezt explicit jelltk is az override kulcsszval. gy a fordt el
tudja dnteni a futsidej tpust, s ez ltal temezi a metdushvsokat. Ez az n.
ksi kts (late binding). A kimenet gy mr nem lehet ktsges.
Mr beszltnk arrl, hogyan pl fel a metdustbla, a fordt megkeresi a
legkorbbi implementcit, s most mr azt is tudjuk, hogy az els ilyen
- 140 -
implementci egy virtulis metdus lesz, azaz a keress legksbb az els virtulis
vltozatnl megll.
- 141 -
class Program
{
static public void Main()
{
// Animal a = new Animal(); //ez nem fordul le
Dog d = new Dog();
d.Eat();
}
}
- 142 -
Ennek a kdnak hiba nlkl kell fordulnia, hiszen tnylegesen egyszer sem
pldnyostottuk az absztrakt sosztlyt. A fordt csak azt fogja megvizsglni, hogy
mi van a new opertor jobb oldaln, az alaposztly nem rdekli. Termszetesen a
kvetkez esetben nem fordulna le:
animalArray[0] = new Animal("Animal");
- 143 -
21
Interfszek
- 144 -
void Main()
new Dog();
ia = d;
= d;
ia.Eat();
id.Vau();
}
- 145 -
Ez a forrskd lefordul, s a metdust is meg tudjuk hvni, a problma ott van, hogy
kt metdust kellene implementlnunk, de csak egy van viszont a program
mkdik. Nylvn nem ez az elvrt viselkeds, ezrt ilyen esetekben explicit mdon
meg kell mondanunk, hogy melyik metdus/tulajdonsg/etc... melyik interfszhez
tartozik. rjuk t a fenti kdot:
- 146 -
void ITwo.Method()
{
Console.WriteLine("ITwo Method!");
}
- 148 -
22
Opertor kiterjeszts
-(unris)
+
&
==
<=
!
|
!=
~
*
^
>
++
/
<<
<
- 149 -
Mivel definiltunk az osztlyunkon egy sajt opertort gy a fordt tudni fogja, hogy
azt hasznlja s talaktja a mveletet:
MyInt result = MyInt.operator+(x, y);
Mivel ez egy pldny tag ezrt a thist hasznljuk az objektum jellsre, amin
meghvtuk a metdust.
Ha az Equals t megvalstottuk, akkor ezt kell tennnk a szintn az object tl
rkltt GetHashCode metdussal is, gy az osztly hasznlhat lesz
gyjtemnyekkel s a HashTable tpussal is. A legegyszerbb implementci
visszaad egy szmot az adattag(ok)bl szmolva (pl.: hatvnyozs, biteltols, stb):
public override int GetHashCode()
{
return this.Value << 2;
}
// 10
// 11
// 12
// 12 (!)
- 151 -
Nzzk az utols sort! Mivel ynak a postfixes formban adtunk rtket, ezrt 11et
kellene tartalmaznia, ehelyett x++ esetben pontosan ugyanaz trtnik, mint ha ++xet rtunk volna.
A problma, hogy kifejezetten postfixes opertort nem tudunk definilni, az ltalunk
ksztett kd minden esetben a prefix opertort jelenti. Viszont meghvhatjuk az
ltalunk definilt opertorokat postfixes alakban, ekkor az adott objektumot eltrolja a
rendszer, meghvja az rtket nvel kdrszletet, s visszadja az els lpsben
flrerakott rtket. Ugye ez rtktpusok esetben tkletesen mkdik, de
referenciatpusoknl az els lpsben nem az rtket hanem a referencit troljuk,
vagyis a ksbbi vltozs itt is rvnyben lesz.
Ugyanakkor ltezik mdszer arra, hogy mgis megoldjuk a fenti problmt: az
opertornak egy teljesen j objektumot kell visszaadnia, ekkor erre mr nem mutat
korbbi referencia, vagyis biztonsgosan hasznlhat (viszont az j mvelet (az
objektum ltrehozsa) miatt a teljestmnyre negatv hatssal lehet (ez persze nha
elfogadhat)).
- 152 -
- 153 -
23
Kivtelkezels
A try blokk jelli ki a lehetsges hibaforrst, a catch pedig elkapja a megfelel kivtelt
(arra figyeljnk, hogy ezek is blokkok, azaz a blokkon bell deklarlt vltozk a
blokkon kvl nem lthatak). A fenti programra a kvetkez lesz a kimenet:
A hiba: Index was outside the bounds of the array.
Lthat, hogy a kivtel egy objektum formjban ltezik. Minden kivtel se a
System.Exception osztly, gy ha nem specilisan egy kivtelt akarunk elkapni, akkor
rhattuk volna ezt is:
- 154 -
try
{
array[2] = 10;
}
catch(System.Exception e)
{
Console.WriteLine(e.Message);
}
A catchnek nem ktelez megadni a kivtel tpust, ekkor minden kivtelt elkap:
try
{
throw new System.Exception();
}
catch
{
Console.WriteLine("Kivtel. Hurr!");
}
Lthat, hogy a catchnek elg csak a kivtel tpust megadni, persze ekkor nem
hasznlhatjuk a kivtelobjektumot.
- 156 -
using System;
class MyException : System.Exception
{
public MyException() { }
public MyException(string message)
: base(message)
{
}
class Program
{
static public void Main()
{
try
{
throw new MyException("Kivtel. Hurr!");
}
catch(MyException e)
{
Console.WriteLine(e.Message);
}
}
}
- 157 -
- 158 -
24
amely
megvalstja
az
IEnumerator
IEnumerable
Megolds
Korbban mr tallkoztunk a foreach ciklussal, s mr tudjuk, hogy csak olyan
osztlyokon kpes vgigiterlni, amelyek megvalstjk az IEnumerator s
IEnumerable interfszeket. Mindkett a System.Collections nvtrben tallhat.
Elsknt nzzk az IEnumerable interfszt:
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
- 159 -
- 161 -
}
Console.WriteLine();
}
- 162 -
class Matrix
{
int[,] matrix;
public Matrix(int n, int m)
{
matrix = new int[n, m];
}
public int N
{
get { return matrix.GetLength(0); }
}
public int M
{
get { return matrix.GetLength(1); }
}
public int this[int idxn, int idxm]
{
get { return matrix[idxn, idxm]; }
set { matrix[idxn, idxm] = value; }
}
static public Matrix operator+(Matrix lhs, Matrix rhs)
{
if(lhs.N != rhs.N || lhs.M != rhs.M) return null;
Matrix result = new Matrix(lhs.N, lhs.M);
for(int i = 0;i < lhs.N;++i)
{
for(int j = 0;j < lhs.M;++j)
{
result[i, j] = lhs[i, j] + rhs[i, j];
}
}
return result;
}
}
- 163 -
25
Delegateek
A delegateek olyan tpusok, amelyek egy vagy tbb metdusra hivatkoznak. Minden
delegate klnll objektum, amely egy listt trol a meghvand metdusokrl
(rtelemszeren ez egyttal ers referencia is lesz a metdust szolgltat osztlyra).
Nemcsak pldny-, hanem statikus metdusokra is mutathat. Egy delegate
deklarcijnl megadjuk, hogy milyen szignatrval rendelkez metdusok
megfelelek:
delegate int TestDelegate(int x);
A hasznlata:
TestDelegate dlgt = Pow;
int result = dlgt(10);
- 164 -
a szignatrjuk
using System;
class Program
{
public delegate void Dlgt1();
public delegate void Dlgt2();
static public void Method() { }
static public void Main()
{
Dlgt1 d1 = Program.Method;
Dlgt2 d2 = d1; // ez hiba
}
}
c1
c2
+=
+=
= new C1();
= new C1();
c1.CMethod;
c2.CMethod;
- 166 -
- 167 -
Egy nvtelen metdus elri az t trol blokk loklis vltozit s mdosthatja is ket:
using System;
class Program
{
public delegate void Test();
static public void Main()
{
int x = 10;
Test t = delegate()
{
x = 11;
Console.WriteLine(x);
};
t();
}
}
Ilyenkor figyelni kell arra, hogy a kls vltozra a delegate is ers referencival
mutat, vagyis a vltoz akkor vlik eltakarthatv, ha a delegate maga is rvnyt
veszti.
Nvtelen metdus nem hasznlhat semmilyen ugr utastst (pl.: goto, break, stb...).
- 168 -
25. Esemnyek
Egy osztly esemnyeket (event) hasznlhat, hogy a sajt llapota megvltozsakor
rtestsen ms osztlyokat. Ehhez a megfigyel osztlyoknak fel kell iratkozni a
megfigyelt osztly esemnyre azltal, hogy az elbbiek rendelkeznek egy, az
esemnynek megfelel szignatrj metdussal, n. esemnykezelvel. Az
esemny megtrtntekor ezek a metdusok fognak lefutni. Eddig ez nagyon gy
hangzik, mintha a delegateekrl beszltnk volna, s valban egy esemny
tulajdonkppen egy specilis delegate, mindssze hrom dologban klnbznek:
-
amelyek
- 169 -
class Program
{
static public void Handler(string message)
{
Console.WriteLine(message);
}
static public void Main()
{
Test t = new Test();
t.TestStatusChange += Program.Handler;
t.Data = 11;
}
}
- 171 -
Lthat, hogy a kliensek kezelse nagyon egyszer, mindssze egy mveletet kell
elvgeznnk az esemnyekre val feliratkozsrt/leiratkozsrt. Nzzk meg a
kliens osztlyt:
class Client
{
public Client(string name)
{
Name = name;
}
public string Name { get; set; }
public void ServerMessageHandler(object sender, ServerEventArgs e)
{
Console.WriteLine("{0} zenetet kapott: {1}",
this.Name, e.Message);
}
}
Vgl a Main:
static public void Main()
{
Server server = new Server();
Client c1 = new Client("Jzsi");
Client c2 = new Client("Bla");
Client c3 = new Client("Tomi");
server.Connect(c1);
server.Connect(c2);
server.Disconnect(c1);
server.Connect(c3);
}
- 172 -
26
Generikusok
Fordtskor csak azt tudja ellenrizni, hogy ltez tpust adtunke meg, gy nem
tudhatja a fordt, hogy sikeres lesze a vgrehajts, ezrt a fenti kd az sszeads
miatt (nem felttlenl valstja meg minden tpus) rossz.
- 174 -
- 175 -
T
T
T
T
T
T
:
:
:
:
:
:
alaposztly
interfsz
osztly
struktra
new()
U
- 176 -
class Test<T>
where T : IEnumerable
{
}
- 177 -
26.4 rklds
Generikus osztlybl szrmaztathatunk is, ekkor vagy az sosztly egy specializlt
vltozatt vesszk alapul, vagy a nyers generikus osztlyt:
class Base<T>
{
}
class Derived<T> : Base<T>
{
}
//vagy
class IntDerived : Base<int>
{
}
- 178 -
26.6.1 List<T>
A List<T> az ArrayList generikus, ersen tpusos megfelelje. A legtbb esetben a
List<T> hatkonyabb lesz az ArrayList nl, emellett pedig tpusbiztos is.
Amennyiben rtktpussal hasznljuk a List<T>-t az alaprtelmezetten nem ignyel
bedobozolst, de a List<T> rendelkezik nhny olyan mvelettel, amely viszont igen,
ezek fleg a keresssel kapcsolatosak. Azrt, hogy az ebbl kvetkez
teljestmnyromlst elkerljk, a hasznlt rtktpusnak meg kell valstania az
IComparable s az IEquatable interfszeket (a legtbb beptett egyszer
(rtk)tpus ezt meg is teszi) (ezeket az interfszeket az sszes tbbi gyjtemny is
ignyli).
using System;
using System.Collections.Generic;
class Program
{
static public void Main()
{
List<int> list = new List<int>();
for(int i = 0;i < 10;++i)
{
list.Add(i);
}
- 179 -
Megkereshetjk az sszes olyan elemet is, amely eleget tesz egy felttelnek a Find
s FindAll metdusokkal. Elbbi az els, utbbi az sszes megfelel pldnyt adja
vissza egy List<T> szerkezetben:
using System;
using System.Collections.Generic;
class Program
{
static public void Main()
{
List<int> list = new List<int>();
Random r = new Random();
for(int i = 0;i < 100;++i)
{
list.Add(r.Next(1000));
}
Console.WriteLine("Az elso pros szm a listban: {0}",
list.Find(delegate(int item)
{
return item % 2 == 0;
}));
List<int> evenList = list.FindAll(delegate(int item)
{
return item % 2 == 0;
});
Console.WriteLine("Az sszes pros elem a listban:");
evenList.ForEach(delegate(int item)
{
Console.WriteLine(item);
});
}
}
- 180 -
jdonsgot jelent a listn metdusknt hvott foreach ciklus. Ezt a C# 3.0 vezette be
s az sszes generikus adatszerkezet rendelkezik vele, lnyegben teljesen
ugyangy mkdik mint egy igazi foreach. paramtereknt egy void Method(T
item) szignatrj metdust (vagy nvtelen metdust) vr, ahol T a lista elemeinek
tpusa.
- 181 -
26.6.4 LinkedList<T>
A LinkedList<T> egy ktirny lncolt lista. Egy elem beillesztse illetve eltvoltsa
O(1) nagysgrend mvelet. A lista minden tagja klnll objektum, egy-egy
LinkedListNode<T> pldny. A LLN<T> Next s Previous tulajdonsgai a megelz
illetve a kvetkez elemre mutatnak.
A lista First tulajdonsga az els, Last tulajdonsga pedig az utols tagra mutat.
Elemeket az AddFirst (els helyre szr be) s AddLast (utols helyre tesz)
metdusokkal tudunk beilleszteni.
using System;
using System.Collections.Generic;
class Program
{
static public void Main()
{
LinkedList<string> list = new LinkedList<string>();
list.AddLast("alma");
list.AddLast("di");
list.AddLast("krte");
list.AddFirst("narancs");
LinkedListNode<string> current = list.First;
while(current != null)
- 182 -
{
Console.WriteLine(current.Value);
current = current.Next;
}
Ebben a pldban bejrunk egy lncolt listt, a kimeneten a narancs elemet ltjuk
majd els helyen, mivel t az AddFirst metdussal helyeztk be.
26.6.5 ReadOnlyCollection<T>
Ahogy a nevbl ltszik ez az adatszerkezet az elemeit csak olvassra adja oda. A
listhoz nem adhatunk j elemet sem (ezt nem is tmogatja), csakis a konstruktorban
tlthetjk fel.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel; // ez is kell
class Program
{
static public void Main()
{
List<string> list = new List<string>()
{
"alma", "krte", "di"
};
ReadOnlyCollection<string> roc = new
ReadOnlyCollection<string>(list);
foreach(string item in roc)
{
Console.WriteLine(item);
}
}
- 183 -
A polimorfizmus elve miatt minden olyan helyen, ahol egy Person objektum
hasznlhat ott egy Student objektum is megfelel, legalbbis elvileg. Lssuk, a
kvetkez kdot:
List<Student> studentList = new List<Student>();
List<Person> personList = studentList;
A fenti kt sor, pontosabban a msodik nem fordul le, mivel a .NET nem tekinti
egyenlnek a generikus paramtereket, mg akkor sem, ha azok kompatibilisak
lennnek. Azt mondjuk, hogy a generikus paramterek nem kovarinsak
(covariance). A dolog fordtottja is igaz, vagyis nincs kompatibilits az ltalnosabb
tpusrl a szkebbre sem, nem kontravarinsak (contravariance).
Mirt van ez gy? Kpzeljk el azt a helyzetet, amikor a fenti osztlyokat kiegsztjk
mg egy Teacher osztllyal, amely szintn a Person osztlybl szrmazik. Ha a
generikus paramterek kovarinsan viselkednnek, akkor lehetsges lenne Student
s Teacher objektumokat is egy listba tenni ez pedig azzal a problmval jr, hogy
lehetsges lenne egy elem olyan tulajdonsgt mdostani amellyel nem rendelkezik,
ez pedig nylvn hibt okoz (persze tpusellenrzssel ez is thidalhat, de ezzel az
egsz generikus adatszerkezet rtelmt veszten).
A .NET 4.0 bevezeti a kovarins s kontravarins tpusparamtereket, gy oldva
meg a fent vzolt problmt, hogy a krdses tpusok csak olvashatak illetve csak
rhatak lesznek. A kvetkez pldban egy generikus delegate segtsgvel nzzk
meg az j lehetsgeket (j listaszerkezetet rni bonyolultabb lenne) (a plda
megrtshez szksg van a lambda kifejezsek ismeretre). Elszr egsztsk ki
a Person osztly egy Name tulajdonsggal:
class Student : Person
{
public string Name { get; set; }
}
- 184 -
Most viszont minden mkdik, hiszen biztostottuk, hogy minden tpust megfelelen
kezeljk. Most lssuk a kontravariancit:
delegate void Method<in T>(T t);
class Program
{
static public void Main()
{
Method<Person> m1 = (person) => Console.WriteLine(person.Name);
Method<Student> m2 = m1;
}
}
- 185 -
27
Lambda kifejezsek
Egy olyan metdusra van teht szksg amely egy int tpus bemen paramtert vr
s ugyanilyen tpust ad vissza. A lambda kifejezs bal oldaln a bemen paramter
(x) jobb oldaln pedig a visszadatott rtkrl gondoskod kifejezs (x * x) ll. A
bemen paramternl nem kell (de lehet) explicit mdon jeleznnk a tpust, azt a
fordt magtl kitallja (a legtbb esetre ez igaz, de nha szksg lesz r, hogy
jelljk a tpust).
Termszetesen nem csak egy bemen paramtert hasznlhatunk, a kvetkez
pldban sszeszorozzuk a lambda kifejezs kt paramtert:
using System;
class Program
{
public delegate int IntFunc2(int x, int y);
static public void Main()
{
IntFunc2 func = (x, y) => (x * y);
Console.WriteLine(func(10, 2));
}
}
A generikus paramterek kztt utols helyen mindig a visszatrsi rtk ll, eltte
pedig a bemen paramterek (maximum ngy) kapnak helyet.
using System;
class Program
{
static public void Main()
{
Func<int, int, bool> func = (x, y) => (x > y);
Console.WriteLine(func(10, 5)); // True
}
A Func prja az Action, amely szintn maximum ngy bemen paramtert kaphat, de
nem lehet visszatrsi rtke:
- 187 -
using System;
class Program
{
static public void Main()
{
Action<int> act = (x) => Console.WriteLine(x);
act(10);
}
}
27.2 Kifejezsfk
Generikus kifejezsek segtsgvel felpthetnk kifejezsfkat, amelyek olyan
formban troljk a kifejezsben szerepl adatokat s mveleteket, hogy futsi
idben a CLR ki tudja azt rtkelni. Egy kifejezsfa egy generikus kifejezst kap
generikus paramterknt:
using System;
using System.Linq.Expressions; // ez kell
class Program
{
static public void Main()
{
Expression<Func<int, int, bool>> expression =
(x, y) => (x > y);
Console.WriteLine(expression.Compile().Invoke(10, 2)); // True
}
}
A programban elszr IL kdra kell fordtani (Compile), csak azutn hvhatjuk meg.
- 188 -
local = 100;
}
class Program
{
static public void Main()
{
Test t = new Test();
t.Method();
t.act(100);
}
}
- 189 -
class Test
{
public event EventHandler TestEvent;
Lambda kifejezs helyett n. lambda lltst rtunk, gy akr tbb soros utastsokat
is adhatunk.
- 190 -
28
Attribtumok
Egy attribtumot mindig szgletes zrjelek kzt adunk meg. Ha a programban nem
lenne definilva az adott szimblum a metdus nem futna le.
Szimblumok defincijt mindig a forrsfile elejn kell megtennnk, ellenkez
esetben a program nem fordul le.
Minden olyan osztly, amely brmilyen mdon a System.Attribute absztrakt
osztlybl szrmazik felhasznlhat attribtumknt. Konvenci szerint minden
attribtum osztly neve a nvbl s az utna rt Attribute szbl ll, gy a
Conditional eredeti neve is ConditionalAttribute, de az uttagot tetszs szerint
elhagyhatjuk, mivel a fordt gy is kpes rtelmezni a kdot.
Ahogy az mr elhangzott, mi magunk is kszthetnk attribtumokat:
class TestAttribute : System.Attribute { }
[Test]
class C { }
- 191 -
Ez nem volt tl nehz, persze az attribtum sem nem tl hasznos. Mdostsuk egy
kicsit! Egy attribtum-osztlyhoz tbb szablyt is kthetnk a hasznlatra
vonatkozan, pl. megadhatjuk, hogy milyen tpusokon hasznlhatjuk. Ezeket a
szablyokat az AttributeUsage osztllyal deklarlhatjuk. Ennek az osztlynak egy
ktelezen megadand s kt opcionlis paramtere van: ValidOn illetve
AllowMultiple s Inherited. Kezdjk az elsvel: a ValidOn azt hatrozza meg, hogy
hol hasznlhatjuk az adott attribtumot, pl. csak referenciatpuson vagy csak
metdusoknl (ezeket akr kombinlhatjuk is a bitenknti vagy opertorral(|)).
[AttributeUsage(AttributeTargets.Class)]
class TestAttribute : System.Attribute { }
[Test]
class C { }
[Test] // ez nem lesz j
struct S { }
- 193 -
29
Unsafe kd
Elszr deklarltunk egy unsafe adattagot, mghozz egy int tpusra mutat pointert.
A pointer tpus az rtk- s referenciatpusok mellett a harmadik tpuskategria. A
pointerek nem szrmaznak a System.Objectbl s konverzis kapcsolat sincs
kzttk (br az egyszer numerikus tpusokrl ltezik explicit konverzi).
rtelemszeren boxing/unboxing sem alkalmazhat rajtuk. Egy pointer mindig egy
memriacmet hordoz, amely memriaterleten egy teljesen normlis objektum van.
- 194 -
Pointer csakis a beptett numerikus tpusokra (belertve a char is), logikai tpusokra,
felsorolt tpusokra, ms pointerekre illetve minden olyan ltalunk ksztett struktrra
hivatkozhat, amely nem tartalmaz az eddig felsoroltakon kvl mst. Ezeket a
tpusokat sszefoglal nven unmanaged tpusoknak nevezzk.
Explicit konverzi ltezik brmely kt pointer tpus kztt, ezrt fennllhat a veszlye,
hogy ha A s B pointer nem ugyanakkora mret terletre mutat akkor az Arl Bre
val konverzi nem definilt mkdst okoz:
int x = 10;
byte y = 20;
int* p1 = &x; // ez j
p1 = (int*)&y; // ez nem biztos, hogy j
Implicit konverzi van viszont brmely pointer tpusrl a void* univerzlis pointer
tpusra. A void*-on nem hasznlhat a dereference opertor:
- 195 -
using System;
class Program
{
static public void Main()
{
unsafe
{
int x = 10;
void* p1 = &x;
Console.WriteLine( *((int*)p1) );
}
}
- 196 -
using System;
class Program
{
static public void Main()
{
unsafe
{
int[] array = new int[] { 1, 3, 4, 6, 7 };
int* p = &array;
}
}
}
}
- 197 -
int MessageBox(
HWND hWnd,
// handle of owner window
LPCTSTR lpText,
// address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType
// style of message box
);
Ezen kvl mg tudnunk kell azt is, hogy melyik DLL trolja az adott fggvnyt, ez
jelen esetben a user32.dll lesz.
Mindent tudunk, ksztsk el a programot! A fggvny importlshoz a DllImport
attribtumot fogjuk hasznlni:
using System;
using System.Runtime.InteropServices;
public class Program
{
static public void Main()
{
API.MessageBox(0, "Hello!", "Nincs", 0);
}
}
public class API
{
[DllImport("user32.dll")]
public static extern int MessageBox(int hWnd,
string text, string caption, uint type);
}
- 198 -
30
Tbbszl alkalmazsok
- 199 -
Amennyiben
tudjuk
a
process
azonostjt,
Process.GetProcessById(azonost) metdust is.
akkor
hasznlhatjuk
Elg valszn, hogy a program futsakor kivtelt kapunk, hiszen a szlak listjba
olyan szl is bekerlhet, amely a kirskor mr befejezte futst (ez szinte mindig az
Idle process esetben fordul el, a meggondols hzi feladat, akrcsak a program
kivtel-biztoss ttele).
A fenti osztlyok segtsgvel remekl bele lehet ltni a rendszer lelkbe, az
MSDNen megtalljuk a fenti osztlyok tovbbi metdusait, tulajdonsgait amelyek
az utazshoz szksgesek.
A kvetkez programunk a processek irnytst szemllteti, indtsuk el az Internet
Explorert, vrjunk t msodpercet s lltsuk le:
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
static public void Main()
{
Process explorer = Process.Start("iexplore.exe");
Thread.Sleep(5000);
explorer.Kill();
}
}
- 200 -
30.2 Szlak
Elrkeztnk a fejezet eredeti trgyhoz, mr eleget tudunk ahhoz, hogy megrtsk a
tbbszl alkalmazsok elvt. Els programunkban lekrjk az adott programrsz
szlnak az azonostjt:
- 201 -
using System;
using System.Threading;
class Program
{
static public void Main()
{
Console.WriteLine("Szl-Id: {0}",
Thread.CurrentThread.ManagedThreadId);
}
}
Ez valjban gy nz ki:
public sealed class MyDelegate : System.MulticastDelegate
{
//...metdusok...
public IAsyncResult BeginInvoke(int x, AsyncCallback cb, object state);
public int EndInvoke(IAsyncResult result);
}
- 202 -
using System;
using System.Threading;
class Program
{
public delegate int MyDelegate(int x);
static int Square(int x)
{
Console.WriteLine("Szl-ID: {0}",
Thread.CurrentThread.ManagedThreadId);
return (x * x);
}
static public void Main()
{
MyDelegate d = Square;
Console.WriteLine("Szl-ID: {0}",
Thread.CurrentThread.ManagedThreadId);
IAsyncResult iar = d.BeginInvoke(12, null, null);
Console.WriteLine("BlaBla...");
int result = d.EndInvoke(iar);
Console.WriteLine(result);
}
- 203 -
using System;
using System.Threading;
class Program
{
public delegate int MyDelegate(int x);
static int Square(int x)
{
Console.WriteLine("Szl-ID: {0}",
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(100);
return (x * x);
}
static public void Main()
{
MyDelegate d = Square;
Console.WriteLine("Szl-ID: {0}",
Thread.CurrentThread.ManagedThreadId);
IAsyncResult iar = d.BeginInvoke(12, null, null);
while(!iar.IsCompleted)
{
Console.WriteLine("BlaBla...");
}
int result = d.EndInvoke(iar);
Console.WriteLine(result);
}
Ha futtatjuk ezt a programot, akkor azt fogjuk ltni, hogy nem rja ki az eredmnyt. Ez
azrt van, mert a BlaBla utn a program futsa megll, mivel elrte a Main vgt s
nincs tbb utasts, valamint ez gyorsabban trtnik, minthogy az aszinkron metdus
ksz lenne. pp ezrt rdemes egy ReadKey vagy egy Sleep metdust hasznlni a
program vgn.
A kimenet a kvetkez lesz:
Szl-ID 1
BlaBla...
Szl-ID: 3
Aszinkron szl ksz...
Eredmny: 144
- 205 -
- 206 -
- 207 -
class Program
{
static public void Main()
{
Test t = new Test();
Thread backgroundThread = new Thread(
new ParameterizedThreadStart(t.ThreadInfo));
backgroundThread.Name = "Background-Thread";
backgroundThread.Start("Hello");
}
}
- 208 -
using System;
using System.Threading;
class Test
{
public void ThreadInfo()
{
Thread.Sleep(5000);
Console.WriteLine("Szl-nv: {0}", Thread.CurrentThread.Name);
}
}
class Program
{
static public void Main()
{
Test t = new Test();
Thread backgroundThread = new Thread(
new ThreadStart(t.ThreadInfo));
backgroundThread.IsBackground = true;
backgroundThread.Name = "Background-Thread";
backgroundThread.Start();
}
}
Ez a program semmit nem fog kirni s pont ezt is vrtuk tle, mivel belltottuk az
IsBackground tulajdonsgot, ezrt az ltalunk ksztett szl valdi httrben fut
szl lett, vagyis a fszlnak nem kell megvrnia.
30.6 Szinkronizci
A szlak szinkronizcijnak egy primitvebb formjt mr lttuk a delegateek
esetben, most egy kicsit komolyabban kzeltnk a tmhoz.
Ngyflekppen szinkronizlhatjuk a szlainkat, ezek kzl az els a blokkols.
Ennek mr ismerjk egy mdjt, ez a Thread.Sleep metdus:
using System;
using System.Threading;
class Program
{
static public void Main()
{
Console.WriteLine("Start...");
Thread.Sleep(2000);
Console.WriteLine("Stop...");
}
}
- 209 -
if(t.Join(1000) == false)
{
Console.WriteLine("Az id lejrt...");
t.Abort(); // megszaktjuk a szl futst
}
- 210 -
Thread.Sleep(2);
Console.WriteLine(Test.y / Test.x);
Test.x = 0;
}
}
class Program
{
static public void Main()
{
Thread t1 = new Thread(new ThreadStart(Test.Divide));
Thread t2 = new Thread(new ThreadStart(Test.Divide));
t1.Start();
t2.Start();
}
}
Tegyk fel, hogy megrkezik egy szl, eljut odig, hogy kirja az eredmnyt, s pp
ekkor rkezik egy msik szl is. Megvizsglja a felttelt, rendben tallja s tovbblp.
Ebben a pillanatban azonban az elsknt rkezett szl lenullzza a vltozt, s
amikor a msodik szl osztani akar, akkor kap egy szp kis kivtelt. A Divide
metdus felttelben nem vletlenl van ott a Sleep, ezzel tesznk rla, hogy tnyleg
legyen kivtel, mivel ez egy egyszer program muszj lelasstani egy kicsit az els
szlat (rdemes tbbszr lefuttatni, nem biztos, hogy azonnal kivtelt kapunk).
A mveletet lezrhatjuk a kvetkez mdon:
static object locker = new object();
static public void Divide()
{
lock(locker)
{
if(Test.x != 0)
{
Thread.Sleep(2);
Console.WriteLine(Test.y / Test.x);
Test.x = 0;
}
}
}
A lock kijell egy blokkot, amelyhez egyszerre csak egy szl fr hozz. Ahhoz
azonban, hogy ezt megtehessk ki jellnnk egy n. tokent, amelyet lezrhat. A
tokennek minden esetben referenciatpusnak kell lennie.
A lock helyett bizonyos esetekben egy lehetsges megolds volatile kulcsszval jellt
mezk hasznlata. A jegyzet ezt a tmt nem trgyalja, mivel a megrtshez
tisztban kell lennnk a fordt sajtossgaival, a kvetkez angol nyelv
weboldalon
bvebb
informcit
tall
a
kedves
olvas:
http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/
Termszetesen nem csak statikus metdusokbl ll a vilg, egy normlis metdust
is lezrhatunk, de ilyen esetekben az egsz objektumra kell vonatkoztatni a zrolst,
hogy ne vltozzon meg az llapota egy msik szl keze nyomn:
- 211 -
class Test
{
int x = 10;
int y = 20;
public void Divide()
{
lock(this)
{
if(x != 0)
{
Thread.Sleep(2);
Console.WriteLine(y / x);
x = 0;
}
}
}
}
- 212 -
30.7 ThreadPool
Kpzeljk el a kvetkez szitucit: egy kliens-szerver alkalmazst ksztnk, a
szerver a fszlban figyeli a bejv kapcsolatokat, s ha kliens rkezik, akkor kszt
neki egy szlat majd a httrben kiszolglja. Tegyk mg hozz azt is, hogy a
kliensek viszonylag rvid ideig tartjk a kapcsolatot a szerverrel, viszont sokan
vannak.
Ha gy ksztjk el a programot, hogy a bejv kapcsolatoknak mindig j szlat
ksztnk, akkor nagyon gyorsan teljestmnyproblmkba fogunk tkzni:
- 213 -
Ami elssorban feltnhet, az az, hogy a ThreadPool egy statikus osztly,vagyis nem
tudjuk pldnyostani ehelyett a metdusait hasznlhatjuk. A SetMaxThread metdus
a maximlisan memriban tartott szlak szmt lltja be, az els paramter a
rendes a msodik az aszinkron szlak szmt jelzi (utbbira most nincs szksg
ezrt kapott nulla rtket).
A QueueUserWorkItem metdus lesz a ThreadPool lelke, itt indtjuk tjra az egyes
szlakat. Ha egy feladat bekerl a listra, de nincs az adott pillanatban szabad szl,
akkor addig vr, amg nem kap egyet. A metdus els paramtere egy delegate,
amely olyan metdusra mutathat, amelynek visszatrsi rtke nincs (void) s
egyetlen object tpus paramterrel rendelkezik. Ezt a paramtert adjuk meg a
msodik paramterben.
- 214 -
Fontos tudni, hogy a ThreadPool osztly csakis background szlakat indt, vagyis a
program nem fog vrni amg minden szl vgez hanem kilp. Ennek
megakadlyozsra tettnk a program vgre egy Console.ReadKey parancsot, gy
ltni is fogjuk, hogy mi trtnik ppen (erre pl. a fent emltett kliens-szerver pldban
nincs szksg, mivel a szerver a fszlban vgtelen ciklusban vrja a bejv
kapcsolatokat).
- 215 -
31
Reflection
- 216 -
A felhasznlt InvokeMember
metdus els paramtere annak a
konstruktornak/metdusnak/tulajdonsgnak/ a neve amelyet meghvunk. A
msodik paramterrel jelezzk, hogy mit s hogyan fogunk hvni (a fenti pldban
egy metdust). Kvetkez a sorban a binder paramter, ezzel bellthatjuk, hogy az
rkltt/tlterhelt tagokat hogyan hvjuk meg. Ezutn maga a tpus, amin a hvst
elvgezzk, vgl a hvs paramterei (ha vannak)).
- 217 -
32
llomnykezels
A program pedig:
using System;
using System.IO;
class Program
{
static public void Main()
{
FileStream fs = new FileStream("test.txt", FileMode.Open);
StreamReader sr = new StreamReader(fs);
string s = sr.ReadLine();
while(s != null)
{
Console.WriteLine(s);
s = sr.ReadLine();
}
sr.Close();
fs.Close();
}
Truncate
Vgl a FileSharerel azt lltjuk be, ahogy ms folyamatok frnek hozz a filehoz:
None
Read
Write
ReadWrite
Delete
Inheritable
filet.
Ms folyamat trlhet a filebl (de nem
magt a filet).
A gyermek processzek is hozzfrhetnek
a filehoz.
- 220 -
using System;
using System.IO;
class Program
{
static public void Main()
{
BinaryWriter bw = new BinaryWriter(File.Create("file.bin"));
for(int i = 0;i < 100;++i)
{
bw.Write(i);
}
bw.Close();
BinaryReader br = new BinaryReader(
File.Open("file.bin", FileMode.Open));
while(br.PeekChar() != -1)
{
Console.WriteLine(br.ReadInt32());
}
br.Close();
}
tjt vrja paramterknt), gy a metdusban csak meg kell vizsglni, hogy ppen
melyikkel van dolgunk s tkonvertlni a megfelel tpusra. A vizsglatnl egy
bitenknti s mveletet hajtottunk vgre, hogy ez mirt s hogyan mkdik, annak
meggondolsa az olvas feladata.
Eddig csak informcikat
knyvtrstruktrt:
krtnk le,
most
megtanuljuk
mdostani
is
using System;
using System.IO;
class Program
{
static public void Main()
{
string dirPath = "C:\\test";
string filePath = dirPath + "\\file.txt";
// ha nem ltezik a knyvtr
if(Directory.Exists(dirPath) == false)
{
// akkor elksztjk
Directory.CreateDirectory(dirPath);
}
FileInfo fi = new FileInfo(filePath);
// ha nem ltezik a file
if(fi.Exists == false)
{
// akkor elksztjk s runk bele
StreamWriter sw = fi.CreateText();
sw.WriteLine("Dio");
sw.WriteLine("Alma");
sw.Close();
}
}
- 223 -
using System;
using System.IO;
class Program
{
static public void Main()
{
MemoryStream mstream = new MemoryStream();
StreamWriter sw = new StreamWriter(mstream);
for(int i = 0;i < 1000;++i)
{
sw.WriteLine(i);
}
sw.Flush();
FileStream fs = File.Create("inmem.txt");
mstream.WriteTo(fs);
sw.Close();
fs.Close();
mstream.Close();
}
}
32.4 XML
Az XML ltalnos cl lernyelv, amelynek elsdleges clja strukturlt szveg s
informci megosztsa az interneten keresztl. Lssunk egy pldt:
<?xml version="1.0" encoding="UTF-8" ?>
<list>
<item>1</item>
<item>2</item>
<item>3</item>
</list>
Az els sor megmondja, hogy melyik verzit s milyen kdolssal akarjuk hasznlni,
ezutn kvetkeznek az adatok. Minden XML dokumentum egyetlen gykrelemmel
rendelkezik (ez a fenti pldban a <list>), amelynek minden ms elem a
gyermekeleme (egyttal minden nem-gykrelem egy msik elem gyermeke kell
legyen, ez nem felttlenl jelenti a gykrelemet). Minden elemnek rendelkeznie kell
nyit (<list>) s zr (</list>) tagekkel. res elemeknl ezeket egyszerre is
deklarlhatjuk (<res />). Az egyes elemek trolhatnak attribtumokat a kvetkez
formban:
<item value="10" />
<item value="10"></item>
A .NET Framework ersen pt az XMLre, mind offline (konfigurcis fileok, inmemory adatszerkezetek) mind online (SOAP alap informcicsere, etc...) tren.
A szmunkra szksges osztlyok a System.Xml nvtrben vannak, a kt
legalapvetbb ilyen osztly az XmlReader s az XmlWriter. Ezeknek az absztrakt
osztlyoknak a segtsgvel hajthatak vgre a szoksos irs/olvass mveletek.
Elszr nzzk meg, hogyan tudunk beolvasni egy XML filet. A megnyitshoz az
XmlReader egy statikus metdust a Createet fogjuk hasznlni, ez egy streamtl
kezdve egy szimpla filenvig mindent elfogad:
XmlReader reader = XmlReader.Create("test.xml");
- 225 -
Elkezdtk az adatok feltltst, s beszrtunk egy kommentet is. A file tartalma most
a kvetkez:
<?xml version="1.0" encoding="utf-8"?>
<!--2010.08.20. 12:04:21-->
Els paramter az attribtum neve, utna pedig a hozz rendelt rtk jn. Ekkor a file
gy alakul:
<?xml version="1.0" encoding="utf-8"?>
<!--2008.10.17. 20:05:24-->
<PersonsList Note="List of persons">
<Person>
<Name>Reiter Istvan</Name>
<Age>22</Age>
</Person>
</PersonsList>
- 226 -
Vgl, de nem utolssorban a Skip metdus maradt, amely tugorja egy csompont
gyermekeit s a kvetkez azonos szinten lv csompontra ugrik.
- 228 -
Most mr eleget tudunk ahhoz, hogy ksztsnk egy szrializlhat osztlyt. Egy
nagyon fontos dolgot kell megjegyeznnk, az osztlynak csakis a publikus tagjai
szrializlhatak a private vagy protected elrsek automatikusan kimaradnak
(emellett az osztlynak magnak is publikus elrsnek kell lennie). Ezeken kvl
mg szksg lesz egy alaprtelmezett konstruktorra is (a deszrializlshoz, hiszen
ott mg nem tudja, hogy milyen objektumrl van sz).
- 229 -
s az eredmny:
<?xml version="1.0"?>
<ScoreObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PlayerName>Player1</PlayerName>
<Score>1000</Score>
<Date>2008-10-23T16:34:32.734375+02:00</Date>
</ScoreObject>
- 230 -
33
Eddig, amikor egy programot rtunk minden apr vltoztatsnl jra le kellett
fordtani, mg akkor is, ha maga a program nem, csak a hasznlt adatok vltoztak.
Sokkal knyelmesebb lenne a fejleszts s a ksz program hasznlata is, ha a
kls adatokat egy kln fileban trolnnk. Termszetesen ezt megtehetjk gy is,
hogy egy sima szveges filet ksztnk, s azt olvassuk/rjuk, de a .NET ezt is
megoldja helyettnk a konfigurcis fileok bevezetsvel. Ezek tulajdonkppen XML
dokumentumok amelyek a kvetkezkppen plnek fel:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="1" value="alma" />
<add key="2" value="korte" />
</appSettings>
</configuration>
Az els sor egy szabvnyos XML file fejlce, vele nem kell foglalkoznunk. Sokkal
rdekesebb viszont az appSettings szekci, ahov mr be is raktunk nhny adatot.
Az appSettings az ltalnos adatok trolsra szolgl, vannak specilis szekcik (pl.
adatbzisok elrshez) s mi magunk is kszthetnk ilyet (errl hamarosan).
A file ugyan megvan, de mg nem tudjuk, hogy hogyan hasznljuk fel azt a
programunkban. A konfig file neve mindig alkalmazsneve.exe.config formban
hasznland (vagyis a main.cs forrshoz ha nem adunk meg mst a
main.exe.config elnevezst kell hasznlnuk), ekkor a fordtsnl ezt nem kell kln
jellni, automatikusan felismeri a fordtprogram, hogy van ilyennk is. rjunk is egy
egyszer programot:
using System;
using System.Configuration; // ez kell
class Program
{
static public void Main()
{
string s = ConfigurationManager.AppSettings["1"];
Console.WriteLine(s); // alma
}
}
- 232 -
{
get
{
}
}
A type tulajdonsgnl meg kell adnunk a tpus teljes elrsi tjt nvtrrel egytt (ha
van), illetve azt az assemblyt amelyben a tpus szerepel, ez a mi esetnkben a main
lesz.
Most jjjn az osztly, amely hasznlja az j szekcit, ksztsnk egy
DataHandlerClass.cs nev filet is:
using
using
using
using
System;
System.IO;
System.Text;
System.Configuration;
- 233 -
}
}
}
- 234 -
34
Hlzati programozs
34.1 Socket
A socketek szmtgpes hlzatok (pl. az Internet) kztti kommunikcis
vgpontok. Minden socket rendelkezik kt adattal, amelyek ltal egyrtelmen
azonosthatak s elrhetek: ezek az IP cm s a port szm.
Mi az az IP cm? Az Internet az n. Internet Protocol (IP) szabvnya szerint mkdik.
Eszerint a hlzaton lv minden szmtgp egyedi azonostval IP cmmel
rendelkezik (ugyanakkor egy szmtgp tbb cmmel is rendelkezhet, ha tbb
hlzati hardvert hasznl). Egy IP cm egy 32 bites egsz szm, amelyet 8 bites
rszekre osztunk (pl.: 123.255.0.45), ezltal az egyes szekcik legmagasabb rtke
255 lesz (ez a jellemz az IP negyedik genercijra vonatkozik, az j hatos
generci mr 128 bites cmeket hasznl, igaz ez egyelre kevsb elterjedt (a .NET
tmogatja az IPv4 s IPv6 verzikat is)).
Az IP cmet tekinthetjk az orszg/vros/utca/hzszm ngyesnek, mg a
portszmmal egy szobaszmra hivatkozunk. A portszm egy 16 bites eljel nlkli
szm 1 s 65535 kztt. A portszmokat ki lehet sajttani, vagyis ezltal biztostjk
a nagyobb szoftvergyrtk, hogy ne legyen semmilyen tkzs a termk
hasznlatakor. A portszmok hivatalos regisztrcijt az Internet Assigned Numbers
Authority (IANA) vgzi.
Az 1 s 1023 portokat n. well-knowed portknt ismerjk, ezeken olyan szleskrben
elterjedt szolgltatsok futnak amelyek a legtbb rendszeren megtalhatak
(opercis rendszertl fggetlenl). Pl. a bngszk a HTTP protokollt a 80as
porton rik el, a 23 a Telnet, mg a 25 az SMTP szerver portszma (ezektl el lehet
s biztonsgi okokbl a nagyobb cgek el is szoktak trni, de a legtbb
szmtgpen ezekkel az rtkekkel tallkozunk).
Az 1024 s 49151 kztti portokat regisztrlt portoknak nevezik, ezeken mr olyan
szolgltatsokat is felfedezhetnk amelyek opercis rendszerhez (is) ktttek pl. az
1433 a Microsoft SQL Server portja, ami rtelemszeren Windows rendszer alatt fut.
Ugyanitt megtallunk szoftverhez kttt portot is, pl a World of Warcraft a 3724 portot
hasznlja. Ez az a tartomny amit az IANA kezel.
Az efelettieket dinamikus vagy privt portoknak nevezik, ezt a tartomnyt nem lehet
lefoglalni, programfejleszts alatt clszer ezeket hasznlni.
Mieltt nekillunk a Socket osztly megismersnek, jtsszunk egy kicsit az IP
cmekkel! Azt tudjuk mr, hogy a hlzaton minden szmtgp sajt cmmel
rendelkezik, de szmokat viszonylag nehz megjegyezni, ezrt feltalltk a domainnv vagy tartomnynv intzmnyt, amely rl egy adott IP cmre, vagyis ahelyett,
- 235 -
Most mr ideje mlyebb vizek fel venni az irnyt, elksztjk az els szervernket. A
legegyszerbb mdon fogjuk csinlni a beptett TcpListener osztllyal, amely a
TCP/IP protokollt hasznlja (errl hamarosan rszletesebben). Nzzk meg a forrst:
using System;
using System.Net;
using System.Net.Sockets;
public class Server
{
static public void Main(string[] args)
{
IPAddress ip = IPAddress.Parse(args[0]);
int port = int.Parse(args[1]);
IPEndPoint endPoint = new IPEndPoint(ip, port);
TcpListener server = new TcpListener(endPoint);
server.Start();
Console.WriteLine("A szerver elindult!");
}
- 236 -
using System;
using System.Net;
using System.Net.Sockets;
public class Server
{
static public void Main(string[] args)
{
TcpListener server = null;
try
{
IPAddress ipAddr = IPAddress.Parse(args[0]);
int portNum = int.Parse(args[1]);
IPEndPoint endPoint = new IPEndPoint(ipAddr, portNum);
server = new TcpListener(endPoint);
server.Start();
Console.WriteLine("A szerver elindult!");
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
server.Stop();
Console.WriteLine("A szerver lellt!");
}
}
- 237 -
finally
{
client.Close();
}
}
Persze szerveroldalon egy TcpClient objektumra lesz szksgnk, ezt adja vissza a
metdus.
A programunk jl mkdik, de nem csinl tl sok mindent. A kvetkez lpsben
adatokat kldnk oda-vissza. Nzzk a mdostott klienst:
using
using
using
using
System;
System.Net;
System.Net.Sockets;
System.Text;
class Program
{
static public void Main(string[] args)
{
TcpClient client = null;
NetworkStream stream = null;
try
{
client = new TcpClient(args[0], int.Parse(args[1]));
byte[] data = Encoding.ASCII.GetBytes("Hello szerver!");
stream = client.GetStream();
stream.Write(data, 0, data.Length);
data = new byte[256];
int length = stream.Read(data, 0, data.Length);
Console.WriteLine("A szerver zenete: {0}",
Encoding.ASCII.GetString(data, 0, length));
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
stream.Close();
client.Close();
}
- 238 -
System;
System.Net;
System.Net.Sockets;
System.Text;
System.IO;
class Program
{
static public void Main(string[] args)
{
Socket server = null;
Socket client = null;
try
{
server = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(
IPAddress.Parse(args[0]),
int.Parse(args[1]));
server.Bind(endPoint);
server.Listen(2);
client = server.Accept();
byte[] data = new byte[256];
int length = client.Receive(data);
Console.WriteLine("A kliens zenete: {0}",
Encoding.ASCII.GetString(data, 0, length));
data = new byte[256];
data = Encoding.ASCII.GetBytes("Hello kliens!");
client.Send(data, data.Length, SocketFlags.None);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
client.Close();
server.Close();
}
}
}
- 239 -
System;
System.Net;
System.Net.Sockets;
System.Text;
System.IO;
class Program
{
static public void Main(string[] args)
{
Socket client = null;
try
{
client = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(
IPAddress.Parse(args[0]),
int.Parse(args[1]));
client.Connect(endPoint);
byte[] data = new byte[256];
data = Encoding.ASCII.GetBytes("Hello szerver!");
client.Send(data, data.Length, SocketFlags.None);
data = new byte[256];
int length = client.Receive(data);
Console.WriteLine("A szerver zenete: {0}",
Encoding.ASCII.GetString(data, 0, length));
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
client.Close();
}
}
}
- 240 -
- 241 -
A Pending azt az informcit osztja meg velnk, hogy vrakozik-e bejv kapcsolat.
Tulajdonkppen ez a metdus a kvetkez forrsban szerepl (a Socket osztlyhoz
tartoz) Poll metdust hasznlja:
while(true)
{
if(server.Poll(0, SelectMode.SelectRead))
{
client = server.Accept();
/* itt pedig kommuniklunk a klienssel */
}
else
{
Console.WriteLine("A szerver bejv kapcsolatra vr!");
System.Threading.Thread.Sleep(500);
}
}
A Poll metdus els paramtere egy egsz szm, amely mikromsodpercben (nem
milli-, itt valban a msodperc milliomod rszrl van sz, vagyis ha egy
msodpercig akarunk vrni akkor 1000000ot kell megadnunk) adja meg azt az idt
amg vrunk bejv kapcsolatra/adatra. Amennyiben az els paramter negatv
szm, akkor addig vrunk, amg nincs kapcsolat (vagyis blokkoljuk a programot), ha
pedig nullt adunk meg akkor hasznlhatjuk pre-checkingre is a metdust.
A msodik paramterrel azt mondjuk meg, hogy mire vrunk. A SelectMode felsorolt
tpus hrom taggal rendelkezik:
- 242 -
34.3.1 Select
Az els versenyznk a Socket osztly Select metdusa lesz, amelynek segtsgvel
meghatrozhatjuk egy vagy tbb Socket pldny llapott. Lnyegben arrl van
sz, hogy egy listbl kivlaszthatjuk azokat az elemeket, amelyek megfelelnek
bizonyos kvetelmnyeknek (rhatak, olvashatak). A Select (statikus) metdus
szignatrja a kvetkezkppen nz ki:
public static void Select(
IList checkRead,
IList checkWrite,
IList checkError,
int microSeconds
)
- 243 -
- 244 -
A StringState osztlyt knyelmi okokbl mi magunk ksztettk el, ezt fogjuk tadni a
BeginReceive metdusnak:
class State
{
public const int BufferSize = 256;
public State()
{
Buffer = new byte[BufferSize];
}
public Socket Client { get; set; }
public byte[] Buffer { get; set; }
}
class StringState : State
{
public StringState() : base()
{
Data = new StringBuilder();
}
public StringBuilder Data { get; set; }
}
- 246 -
- 247 -
Minden kliens rendelkezik nvvel is, amely 7 karakter hossz (7 byte) lehet, elsknt
ezt olvassuk be. A GuessNumber metdusnak adjuk t a tippnket s a result
vltozt out paramterknt. Vgl a finally blokkban ellenrizzk, hogy van-e
bejelentkezett kliens, ha pedig nincs akkor j szmot sorsolunk.
Nzzk a GuessNumber metdust:
private void GuessNumber(string name, int number, out int result)
{
lock(locker)
{
if(NUMBER != -1)
{
Console.WriteLine("{0} szerint a szm: {1}",
name, number);
if(NUMBER == number)
{
Console.WriteLine("{0} kitallta a szmot!", name);
result = 0;
NUMBER = -1;
}
else if(NUMBER < number)
{
result = 1;
}
else
{
result = -1;
}
- 248 -
}
else result = 2;
}
Thread.Sleep(300);
}
A metdus trzst le kell zrnunk, hogy egyszerre csak egy szl (egy kliens) tudjon
hozzfrni. Ha valamelyik kliens kitallta szmot, akkor annak -1et adunk vissza,
gy gyorsan ellenrizhetjk, hogy a felttel melyik gba kell bemennnk.
Kliens oldalon sokkal egyszerbb dolgunk van, ezt a forrskdot itt nem
rszletezzk, de megtallhat a jegyzethez tartoz forrsok kztt.
- 249 -
35
LINQ To Objects
- 250 -
using System;
using System.Collections.Generic;
class Program
{
static public void Main()
{
/*Objektum inicializl*/
MyObject mo = new MyObject()
{
Property1 = "value1";
Property2 = "value2";
};
/*Gyjtemny inicializl*/
List<string> list = new List<string>()
{
"alma", "krte", "di", "kakukktojs"
};
35.2 Kivlaszts
A legegyszerbb dolog, amit egy listval tehetnk, hogy egy vagy tbb elemt
valamilyen kritrium alapjn kivlasztjuk. A kvetkez forrskdban pp ezt fogjuk
tenni, egy egsz szmokat tartalmaz List<T> adatszerkezetbl az sszes szmot
lekrdezzk. Termszetesen ennek gy sok rtelme nincsen, de szrsrl majd csak
a kvetkez fejezetben fogunk tanulni.
- 251 -
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static public void Main()
{
List<int> list = new List<int>()
{
10, 2, 4, 55, 22, 75, 30, 11, 12, 89
};
var result = from number in list select number;
foreach(var item in result)
{
Console.WriteLine("{0}", item);
}
}
- 253 -
35.2.1 Projekci
Vegyk a kvetkez egyszer osztly-hieraarchit:
class Address
{
public string Country { get; set; }
public int PostalCode { get; set; }
public int State { get; set; }
public string City { get; set; }
public string Street { get; set; }
}
class Customer
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set;}
public string Email { get; set; }
public string PhoneNumber { get; set; }
public Address Address { get; set; }
}
Minden vsrlhoz tartozik egy Address objektum, amely a vev cmt trolja.
Tegyk fel, hogy egy olyan lekrdezst akarok rni, amely visszaadja az sszes vev
nevt, email cmt s telefonszmt. Ez nem egy bonyolult dolog, a kd a kvetkez
lesz:
var result = from customer in custList select customer;
foreach(var customer in result)
{
Console.WriteLine("Nv: {0}, Email: {1}, Telefon: {2}",
customer.FirstName + + customer.LastName,
customer.Email, Customer.PhoneNumber);
}
35.2.2 Let
A let segtsgvel a lekrdezs hatkrn belli vltozkat hozhatunk ltre,
amelyek segtsgvel elkerlhetjk egy kifejezs ismtelt felhasznlst. Nzznk
egy pldt:
string[] poem = new string[]
{
"Ej mi a k! tykany, kend",
"A szobban lakik itt bent?",
"Lm, csak j az isten, jt d,",
"Hogy flvitte a kend dolgt!"
};
var result = from line in poem
let words = line.Split(' ')
from word in words
select word;
35.3 Szrs
Nylvn nincs szksgnk mindig az sszes elemre, ezrt kpesnek kell lennnk
szrni az eredmnylistt. A legalapvetbb ilyen mvelet a where, amelyet a
kvetkez sablonnal rhatunk le:
from azonost in kifejezs where kifejezs select azonost
Nzznk egy egyszer pldt:
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static public void Main()
{
List<int> list = new List<int>()
{
12, 4, 56, 72, 34, 0, 89, 22
};
var result1 = from number in list
where number > 30
- 255 -
select number;
var result2 = list.Where(number => number > 30);
var result3 = (from number in list select number)
.Where(number => number > 30);
}
}
- 256 -
Console.WriteLine("{0}", item);
}
35.4 Rendezs
A lekrdezsek eredmnyt knnyen rendezhetjk az orderby utastssal, a
lekrdezs sablonja ebben az esetben gy alakul:
from
azonost
in
kifejezs
where
ascending/descending select kifejezs
kifejezs
orderby
- 257 -
tulajdonsg
35.5 Csoportosts
Lehetsgnk van egy lekrdezs eredmnyt csoportokba rendezni a group
by/GroupBy metdus segtsgvel. A sablon ebben az esetben gy alakul:
from
azonost
in
kifejezs
where
kifejezs
orderby
tulajdonsg
ascending/descending group kifejezs by kifejezs into azonost select kifejezs
Hasznljuk fel az elz fejezetben elksztett program neveit s rendezzk ket
csoportokba a nv els betje szerint:
- 258 -
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static public void Main()
{
List<string> names = new List<string>()
{
"Istvn", "Ivn", "Judit", "Joln", "Jen", "Bla",
"Balzs", "Viktria", "Vazul", "Thtm", "Tams"
};
var result1 = names.OrderBy(name => name[0])
.GroupBy(name => name[0]);
var result2 = from name in names
orderby name[0]
group name by name[0]
into namegroup
select namegroup;
foreach(var group in result1)
{
Console.WriteLine(group.Key);
}
}
Bla
Balzs
Istvn
Ivn
Judit
Joln
Jen
Thtm
Tams
Viktria
Vazul
- 259 -
IEnumerable<IGrouping<TKey, TElement>>
Az IGrouping interfsz tulajdonkppen maga is egy IEnumerable<T> leszrmazott
kiegsztve a rendezshez hasznlt kulccsal, vagyis lnyegben egy lista a listban
tpus adatszerkezetrl van sz.
- 260 -
class Address
{
public string Country { get; set; }
public int PostalCode { get; set; }
public int State { get; set; }
public string City { get; set; }
public string Street { get; set; }
}
class Customer
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set;}
public string Email { get; set; }
public string PhoneNumber { get; set; }
public Address Address { get; set; }
}
Fordtani gy tudunk:
csc main.cs Data.cs
- 261 -
class Product
{
public int ID { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
}
- 262 -
- 263 -
System;
System.Collections;
System.Collections.Generic;
System.Linq;
class Program
{
static public void Main()
{
ArrayList list = new ArrayList();
list.Add("alma");
list.Add("di");
list.Add(12345);
var result1 = from item in list.Cast<string>()
select item;
var result2 = from item in list.OfType<string>()
select item;
- 264 -
System;
System.Collections;
System.Collections.Generic;
System.Linq;
class Program
{
static public void Main()
{
List<int> list = new List<int>()
{
10, 32, 45, 2, 55, 32, 21
};
var result = (from number in list
where number > 20
select number).ToList<int>();
result.ForEach((number) => Console.WriteLine(number));
}
}
- 265 -
- 266 -
- 267 -
Min s Max: a lista legkisebb illetve legnagyobb elemt adjk vissza. Mindkt
opertornak megadhatunk egy szelektor kifejezst, amelyet az sszes elemre
alkalmaznak, s e szerint vlasztjk ki a megfelel elemet:
List<int> list = new List<int>()
{
10, 3, 56, 67, 4, 6, 78, 44
};
var result1 = list.Max(); // 78
var result2 = list.Max((item) => item % 3); // 2
- 268 -
Az els esetben a Sum opertort szimulltuk, ezt nem kell magyarzni. A msodik
vltozatban maximumkeresst vgeztnk, itt megadtunk egy kezdrtket, amelynl
biztosan van nagyobb elem a listban. Vgl a harmadik mveletnl kiszmoltuk a
szmok sszegnek egy szzalkt (itt figyelni kell arra, hogy double tpusknt lssa
a fordt a kezdrtket, hiszen tizedes trtet akarunk visszakapni).
A vgeredmnyt trol vltoz brmilyen tpus lehet, mg tmb is.
35.12.2 Teljestmny
Nagyon knnyen azt gondolhatjuk, hogy a processzorok szmnak nvelsvel
egyenes arnyban n a teljestmny, magyarul kt processzor ktszer gyorsabb,
mint egy. Ez az llts nem teljesen igaz (ezt ksbb a sajt szemnkkel is ltni
fogjuk), ezt pedig Gene Amdahl bizonytotta (Amdahls Law), miszerint:
- 269 -
Knnyen kiszmolhat, hogy az eredmny 1/0,55 (1,81) lesz vagyis 81% -os
teljestmnynvekedst rhetnk el kt processzor bevezetsvel. Vegyk szre,
hogy a processzorok szmnak nvelsvel P/N a nullhoz tart, vagyis
kimondhatjuk, hogy minden prhuzamosthat feladat maximum 1/(1 P)
nagysgrend teljestmnynvekedst eredmnyezhet (felttelezve, hogy mindig
annyi processzor ll rendelkezsnkre, hogy P/N a lehet legkzelebb legyen
nullhoz: ez nem felttlenl jelent nagyon sokat, a plda esetben 5 processzor mr
550%-os nvekedst jelent, innen pedig egyre lassabban n az eredmny, mivel
ekkor P/N rtke mr 0,18, hat processzornl 0,15 s gy tovbb), teht a fenti
konkrt esetben a maximlis teljestmny a hagyomnyos futsid tzszerese lehet
(1 / (1 0,9), vagyis pontosan az az egy ra, amelyet a nem prhuzamosthat
programrsz hasznl fel.
- 270 -
Lssuk az eredmnyt:
- 271 -
- 272 -
35.12.4 Rendezs
Nzzk a kvetkez kdot:
List<int> list = new List<int>()
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
};
var result1 = from x in list select x;
var result2 = from x in list.AsParallel() select x;
- 273 -
35.12.5 AsSequential
Az AsSequential metdus pp ellenkezje az AsParallelnek, vagyis
szablyozhatjuk, hogy egy lekrdezs mely rsze legyen szekvencilis s melyik
prhuzamos. A kvetkez pldban megnzzk, hogy ez mirt j neknk. A PLINQ
egyelre mg nem teljesen kiforrott, annak a szablyai, hogy mely opertorok
lesznek mindig szekvencilisan kezelve a jvben valsznleg vltozni fognak, ezrt
a pldaprogramot illik fenntartssal kezelni:
var result = (from x in list.AsParallel() select x).Take(10);
Most pontosan azt kapjuk majd, amire vrunk, a bels prhuzamos mveletsor
vgeztvel visszavltottunk szekvencilis mdba, vagyis a Take nem fogja vissza a
sebessget.
- 274 -
36
Visual Studio
- 275 -
Amennyiben a Show all settings jellngyzet res, akkor jelljk be, majd a
megfelen listbl vlasszuk ki a Startupot:
- 276 -
- 277 -
Az sln file a projectet tartalamz n. Solutiont rja le, ez lesz minden project gykere
(egy Solution tartalmazhat tbb projectet is). Ez a file egy egyszer szveges file,
valami ilyesmit kell ltnunk:
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApplication1",
"ConsoleApplication1\ConsoleApplication1.csproj", "{4909A576-5BF0-48AA-AB70-4B96835C00FF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4909A576-5BF0-48AA-AB70-4B96835C00FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4909A576-5BF0-48AA-AB70-4B96835C00FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4909A576-5BF0-48AA-AB70-4B96835C00FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4909A576-5BF0-48AA-AB70-4B96835C00FF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
36.2 Fellet
Trjnk most vissza a VShez s nzzk meg, hogy miknt pl fel a kezelfellet.
Kezdjk a Solution Explorerrel, amelyben az aktulis Solution elemeit kezelhetjk.
Amennyiben nem ltjuk ezt az ablakot (ha az Auto Hide be van kapcsolva, akkor
csak egy flecske jelenik meg az ablak szln), akkor a View menben keressk
meg.
- 278 -
- 279 -
36.3 Debug
A Visual Studio segtsgvel a programok javtsa, illetve a hibk oknak feldertse
sem okoz nagy nehzsget. Ebben a rszben elsajttjuk a hibakeress alapjait:
elsknt ismerkedjnk meg a breakpoint (vagy trspont) fogalmval. Nylvn gy
tudjuk a legjobban felderteni a programjaink hibit, ha mkds kzben lthatjuk az
objektumok llapott. Erre olyan fapados mdszereket is hasznlhatunk, mint, hogy
kirjuk a konzolra ezeket az rtkeket. Ennek persze megvan a maga htrnya,
hiszen egyrszt be kell gpelni a parancsokat, msrszt beszennyezzk a
forrskdot ami gy nehezebben olvashatv vlik. A breakpointok segtsgvel a
- 280 -
Ezutn, ha futtatjuk a programot, akkor ezen a ponton a futsa megll. Fontos, hogy
a trst tartalmaz sor mr nem fog lefutni, vagyis a fenti kpen s rtke mg baba
marad.
- 281 -
- 282 -
37
Osztlyknyvtr
s gy fordtjuk:
csc /reference:TestLib.dll main.cs
- 283 -
- 284 -
- 285 -
- 286 -