Si të konfiguroni telefonat inteligjentë dhe PC. Portali informativ
  • në shtëpi
  • OS
  • Operatorët janë të mprehtë. Shprehjet e kushtëzuara

Operatorët janë të mprehtë. Shprehjet e kushtëzuara

Përditësimi i fundit: 19.06.2017

C # përdor shumicën e operacioneve që përdoren në gjuhë të tjera programimi. Operacionet paraqesin veprime specifike mbi operandët që janë pjesëmarrës në operacion. Operandi mund të jetë një ndryshore ose ndonjë vlerë (për shembull, një numër). Operacionet mund të jenë unare (të kryera në një operand), binar - në dy operandë dhe tresh - të kryera në tre operandë. Le të shqyrtojmë të gjitha llojet e operacioneve.

Veprimet aritmetike binare:

    Operacioni i mbledhjes së dy numrave:

    Int x = 10; int z = x + 12; // 22

    Operacioni i zbritjes së dy numrave:

    Int x = 10; int z = x - 6; // 4

    Operacioni i shumëzimit të dy numrave:

    Int x = 10; int z = x * 5; // 50

    Veprimi i ndarjes së dy numrave:

    Int x = 10; int z = x / 5; // 2 dyfishtë a = 10; dyfishi b = 3; dyfishtë c = a / b; // 3.33333333

    Kur ndani, mbani në mend se nëse të dy operandët përfaqësojnë numra të plotë, atëherë rezultati gjithashtu do të rrumbullakoset në një numër të plotë:

    Z dyfishtë = 10/4; // rezultati është 2

    Përkundër faktit se rezultati i operacionit vendoset përfundimisht në një variabël të tipit të dyfishtë e cila ju lejon të kurseni pjesë thyesore, por vetë operacioni përfshin dy literale, të cilat si parazgjedhje trajtohen si objekte int, domethënë numra të plotë, dhe rezultati do të jetë i njëjtë me një numër të plotë.

    Për të dalë nga kjo situatë, është e nevojshme të përcaktohen literale ose variabla që marrin pjesë në operacion, saktësisht si tipe të dyfishta ose float:

    Z dyfishtë = 10.0 / 4.0; // rezultati është 2.5

    Operacioni merr pjesën e mbetur të pjesëtimi i numrave të plotë dy numra:

    Dyfishtë x = 10.0; dyfishi z = x% 4.0; // rezultati është 2

Ekziston edhe një numër operacionet unare, në të cilin një operand merr pjesë:

    Operacioni në rritje

    Rritja mund të parashtesohet: ++ x - së pari, vlera e ndryshores x rritet me 1 dhe më pas vlera e saj kthehet si rezultat i operacionit.

    Dhe ka gjithashtu një rritje postfiks: x ++ - së pari, vlera e ndryshores x kthehet si rezultat i operacionit, dhe më pas i shtohet 1.

int x1 = 5; int z1 = ++ x1; // z1 = 6; x1 = 6 Console.WriteLine ($ "(x1) - (z1)"); int x2 = 5; int z2 = x2 ++; // z2 = 5; x2 = 6 Console.WriteLine ($ "(x2) - (z2)");

Operacioni i zvogëlimit ose zvogëlimit të një vlere me një. Ekziston gjithashtu një zvogëlim i parashtesës (--x) dhe një postfiks (x--).

Int x1 = 5; int z1 = --x1; // z1 = 4; x1 = 4 Console.WriteLine ($ "(x1) - (z1)"); int x2 = 5; int z2 = x2--; // z2 = 5; x2 = 4 Console.WriteLine ($ "(x2) - (z2)");

Kur kryeni disa veprime aritmetike në të njëjtën kohë, merrni parasysh rendin në të cilin ato kryhen. Prioriteti i operacioneve nga më i larti tek më i ulëti:

    Rritje, pakësim

    Shumëzimi, pjesëtimi, marrja e mbetjes

    Mbledhja, zbritja

Kllapat përdoren për të ndryshuar rendin e operacioneve.

Konsideroni një grup operacionesh:

Int a = 3; int b = 5; int c = 40; int d = c --- b * a; // a = 3 b = 5 c = 39 d = 25 Console.WriteLine ($ "a = (a) b = (b) c = (c) d = (d)");

Këtu kemi të bëjmë me tre veprime: zvogëlim, zbritje dhe shumëzim. Së pari, c zvogëlohet, pastaj b * a shumëzohet dhe më pas zbritet. Kjo është, në fakt, grupi i operacioneve dukej kështu:

Int d = (c -) - (b * a);

Por me ndihmën e kllapave, ne mund të ndryshojmë rendin e veprimeve, për shembull, si më poshtë:

Int a = 3; int b = 5; int c = 40; int d = (c - (- b)) * a; // a = 3 b = 4 c = 40 d = 108 Console.WriteLine ($ "a = (a) b = (b) c = (c) d = (d)");

Asociativiteti i operatorëve

Siç u përmend më lart, veprimet e shumëzimit dhe pjesëtimit kanë të njëjtin përparësi, por atëherë cili do të jetë rezultati në shprehjen:

Int x = 10/5 * 2;

A duhet ta interpretojmë këtë shprehje si (10/5) * 2 apo si 10 / (5 * 2)? Në të vërtetë, në varësi të interpretimit, do të marrim rezultate të ndryshme.

Kur operacionet kanë të njëjtën përparësi, radha e vlerësimit përcaktohet nga shoqëria e operatorëve. Ekzistojnë dy lloje të operatorëve në varësi të asociativitetit:

    Operatorët shoqërues të majtë që ekzekutojnë nga e majta në të djathtë

    Operatorët shoqërues të djathtë që ekzekutojnë nga e djathta në të majtë

Gjithçka operatorët aritmetikë(me përjashtim të shtimit dhe zvogëlimit të parashtesës) janë asociative majtas, domethënë kryhen nga e majta në të djathtë. Prandaj, shprehja 10/5 * 2 duhet të interpretohet si (10/5) * 2, domethënë, rezultati do të jetë 4.

Operatorët e marrëdhënieve dhe operatorët logjikë

Në shënimin operator relacioni dhe operator logjik afati marrëdhënie nënkupton një marrëdhënie që mund të ekzistojë midis dy kuptimeve dhe termit logjike- marrëdhënia midis vlerave logjike "e vërtetë" dhe "e rreme". Dhe për shkak se operatorët relacionalë japin rezultate të vërteta ose të rreme, ata shpesh përdoren në lidhje me operatorët logjikë. Është për këtë arsye që ato konsiderohen së bashku.

Më poshtë janë operatorët relacionalë:

Operatorët Boolean përfshijnë si më poshtë:

Rezultati i ekzekutimit të një operatori relacioni ose një operatori logjik është një vlerë boolean e tipit bool.

Në përgjithësi, objektet mund të krahasohen për barazi ose pabarazi duke përdorur operatorët relacionalë == dhe! =. Operatorët e krahasimit, =, mund të aplikohen vetëm për llojet e të dhënave që mbështesin një marrëdhënie porositjeje. Prandaj, operatorët relacionalë mund të aplikohen për të gjitha llojet e të dhënave numerike. Por vlerat bool mund të krahasohen vetëm për barazi ose pabarazi, pasi vlerat e vërteta dhe të rreme nuk renditen. Për shembull, krahasimi true> false në C # është i pakuptimtë.

Konsideroni një program shembull që demonstron përdorimin e operatorëve relacionalë dhe logjikë:

Përdorimi i Sistemit; duke përdorur System.Collections.Generic; duke përdorur System.Linq; duke përdorur System.Text; namespace ConsoleApplication1 (Programi i klasës (programi statik i zbrazët (kryesor i vargut) (d i shkurtër = 10, f = 12; bool var1 = i vërtetë, var2 = i gabuar; nëse (df) Console.WriteLine ("d> f"); // Krahaso variablat var1 dhe var2 if (var1 & var2) Console.WriteLine ("Ky tekst nuk do të shfaqet"); nëse (! (var1 & var2)) Console.WriteLine ("! (var1 & var2) = e vërtetë"); nëse (var1 | var2) Console.WriteLine ("var1 | var2 = e vërtetë"); if (var1 ^ var2) Console.WriteLine ("var1 ^ var2 = e vërtetë"); Console.ReadLine ();)))

Operatorët Boolean në C # kryejnë operacionet logjike më të zakonshme. Sidoqoftë, ka një sërë operacionesh të kryera sipas rregullave të logjikës formale. Këto operacione boolean mund të ndërtohen duke përdorur operatorë boolean të mbështetur në C #. Prandaj, C # ofron një grup të tillë operatorësh logjikë, i cili është i mjaftueshëm për të ndërtuar pothuajse çdo operacion logjik, duke përfshirë implikimet. Implikimiështë një operacion binar që vlerësohet si i gabuar vetëm nëse operandi i tij i majtë ka kuptimin e vërtetë dhe e drejta është e rreme. (Operacioni i nënkuptimit pasqyron parimin e mëposhtëm: e vërteta nuk mund të thotë e rreme.)

Operacioni i nënkuptimit mund të ndërtohet mbi bazën e një kombinimi të operatorëve logjikë! dhe |:

Operatorë logjikë të shkurtuar

C # gjithashtu ofron të veçanta, i shkurtuar, variante të operatorëve logjikë DHE dhe OR, të krijuara për të marrë kode më efikase. Le ta shpjegojmë këtë shembujt e mëposhtëm operacionet logjike. Nëse operandi i parë i një operacioni logjik AND është false, atëherë rezultati i tij do të jetë fals pavarësisht nga vlera e operandit të dytë. Nëse operandi i parë i një operacioni logjik OR ka një vlerë të vërtetë (true), atëherë rezultati i tij do të ketë një vlerë të vërtetë pavarësisht nga vlera e operandit të dytë. Për shkak të faktit se vlera e operandit të dytë në këto operacione nuk ka nevojë të llogaritet, kursen kohë dhe përmirëson efikasitetin e kodit.

Një operacion i cunguar logjik AND kryhet duke përdorur operator &&, dhe një operacion të shkurtuar logjik OSE duke përdorur operatori ||... Këta operatorë logjikë të shkurtuar korrespondojnë me operatorët e zakonshëm logjik & dhe |. I vetmi ndryshim midis një operatori logjik të cunguar dhe një operatori të zakonshëm është se operandi i tij i dytë vlerësohet vetëm sipas nevojës.

Nuk ka konvertime të nënkuptuara boolean në C #, madje edhe për numrat e plotë llojet aritmetike... Prandaj, shënimi është mjaft i saktë në gjuhën C ++:

ndërk1 = 7;
nëse (k1) Konsolë. WriteLine(" Ne rregull!");

të paligjshme në programet C #. Në fazën e përkthimit, do të ndodhë një gabim sepse kushti i llogaritur ka llojin ndër, dhe shndërrimi i nënkuptuar i këtij lloji në tip bool i zhdukur.

Në C #, rregulla më të rrepta zbatohen edhe për operacionet logjike. Pra, hyrja nëse(k1 && (x> y)), korrekt në C ++, rezulton në një gabim në

Programet C # sepse && përcaktohet vetëm për operandët e tipit bool, dhe në këtë shprehje, një nga operandët është i tipit ndër. Në gjuhën C #, në këto situata, duhet të përdorni hyrjet e mëposhtme:

nëse(k1>0)
nëse((k1>0) && (x> y))

Operacionet logjike ndahen në dy kategori: disa kryhen në vlerat boolean të operandëve, ndërsa të tjerët kryejnë ekzekutimin e një operacioni boolean në bitet e operandëve. Për këtë arsye, ekzistojnë dy operatorë unarë të mohimit në C # - mohimi logjik, i specifikuar nga operatori!, dhe mohimi bit, i specifikuar nga operatori ~. I pari përcaktohet mbi një operand të llojit bool, e dyta - mbi një operand të një tipi numër të plotë, duke filluar me llojin ndër dhe më lart (ndër, unint, gjatë, gjatë). Rezultati i operacionit në rastin e dytë është një operand në të cilin çdo bit zëvendësohet nga plotësuesi i tij. Le të japim një shembull:

/// < përmbledhje>
/// Shprehjet e Bulit
/// përmbledhje>
publikei pavlefshëmLogjika() {
// operacionet e mohimit ~,!
bool b1, b2;
b1= 2*2 == 4;
b2= b1;
// b2 = ~ b1;
uint j1= 7, j2;
j2= ~ j1;
// j2= j1;
int j4= 7, j5;
j5= ~ j4;
Console.WriteLine ("uint j2= " + j2+ " int j5= " + j5);
} // Logjika

Në këtë fragment komentohen deklaratat që çojnë në gabime. Në rastin e parë, u bë një përpjekje për të aplikuar operacionin e mohimit bit në një shprehje si bool, në të dytën, mohimi logjik u aplikua për të dhënat e numrave të plotë. Të dyja janë të paligjshme në C #. Vini re interpretimet e ndryshme të mohimit bit për llojet e numrave të plotë të panënshkruar dhe të nënshkruar. Për variablat j5 dhe j2 vargu i bitit që përcakton vlerën është i njëjtë, por interpretohet ndryshe. Përfundimi përkatës është ky:

unintj2 = 4294967288
ndërj5 = -8.

Operacionet logjike binare " && - e kushtëzuar DHE "dhe" || - të kushtëzuara OR "përcaktohen vetëm mbi të dhënat e llojit bool. Operacionet quhen të kushtëzuara ose të shkurtra, sepse llogaritja e operandit të dytë varet nga vlera tashmë e llogaritur e operandit të parë. Vlera e operacioneve logjike të kushtëzuara qëndron në efikasitetin e tyre për sa i përket kohës së ekzekutimit. Ata shpesh ju lejojnë të llogaritni shprehje boolean kjo ka kuptim, por në të cilën operandi i dytë është i papërcaktuar. Le të marrim si shembull problemin klasik të kërkimit sipas një modeli në një grup, kur kërkohet një element me një vlerë (model) të caktuar. Mund të ketë ose jo një element të tillë në grup. Këtu është një zgjidhje tipike për këtë problem në një formë të thjeshtuar, por përcjell thelbin e çështjes:

// E kushtëzuarDhe- &&
int [] ar= { 1, 2, 3 };
int search= 7;
int i= 0;
nderkohe une< ar.Gjatësia)&& (ar [i]!= kërko)){
i ++;
}
nese une< ar.Gjatësia)Console.WriteLine ("Mostragjetur");
tjetërConsole.WriteLine ("Mostrajogjetur");

Nëse vlera e ndryshores kërkimi(modeli) nuk përputhet me asnjë nga vlerat e elementeve të grupit ar, pastaj kontrolli i fundit i gjendjes së ciklit derisa do të ekzekutohet nëse vlera i, të barabartë ar. Gjatësia. Në këtë rast, operandi i parë do të marrë vlerën i rremë, dhe megjithëse operandi i dytë nuk është i përcaktuar, cikli do të përfundojë normalisht. Operandi i dytë është i papërcaktuar në kontrolli i fundit sepse indeksi i një elementi në grup është jashtë rrezes (në C #, indeksimi i elementeve fillon me zero).

Tre binare operacionet bitwise- "& - DHE", "| - OSE "," ^ - XOR "përdoren në dy mënyra. Ato përcaktohen si më sipër llojet e numrave të plotë ndër, dhe mbi llojet boolean. Në rastin e parë, ato përdoren si operacione bitwise, në të dytin, si operacione të zakonshme logjike. Ndonjëherë është e nevojshme që të dy operandët të llogariten në çdo rast, atëherë këto operacione nuk mund të shmangen. Këtu është një shembull i përdorimit të tyre për herë të parë:

// Operacionet logjike bitwiseDhe, Ose, XOR(&,|,^)
int k2= 7, k3= 5, k4, k5, k6;
k4= k2& k3;
k5= k2 | k3;
k6= k2 ^k3;
Console.WriteLine ("k4= " + k4+ " k5= " + k5+ " k6= " + k6);

Rezultatet e daljes:

k4 = 5 k5 = 7 k6 =2

Këtu është një shembull i një kërkimi modeli duke përdorur logjikën DHE: i= 0;

kërkimi= ar;
nderkohe une< ar.Gjatësia)& (ar [i]!= kërko)) i ++;
nese une< ar.Gjatësia)Console.WriteLine ("Mostragjetur");
tjetër cConsole.WriteLine ("Mostrajogjetur");

Ky fragment është i garantuar të ketë një model kërkimi në grup dhe fragmenti do të ekzekutohet me sukses. Në të njëjtat raste kur grupi nuk përmban një element kërkimi, do të bëhet një përjashtim. Kuptimi kuptimplotë i një procedure të tillë - shfaqja e një përjashtimi - mund të jetë një shenjë e një gabimi në të dhëna, gjë që kërkon trajtim të veçantë të situatës.

KAPITULLI 10. Shprehjet dhe operatorët

Në këtë kapitull, ne do të shikojmë themelin e çdo gjuhe programimi - aftësinë e saj për të kryer detyra dhe krahasime duke përdorur operatorë. Do të shohim se cilët janë operatorët në C # dhe cila është përparësia e tyre, dhe më pas do të zhytemi në kategoritë individuale të shprehjeve për kryerjen e veprimeve aritmetike, caktimin e vlerave dhe krahasimin e operandëve.

Operatorët

Një operator është një simbol që tregon një operacion që duhet të kryhet në një ose më shumë argumente. Kur ekzekutohet deklarata, merret rezultati. Sintaksa për përdorimin e operatorëve është paksa e ndryshme nga metodat e thirrjes dhe duhet të dini formatin e shprehjeve që përmbajnë operatorë në C # si në pjesën e pasme të dorës. Ashtu si me shumicën e gjuhëve të tjera, semantika e operatorëve në C # ndjek rregullat dhe shënimet e njohura për ne nga shkolla. Operatorët Bazë në C # përfshin shumëzimin (*), pjesëtimin (/), mbledhjen dhe plus unar (+), zbritjen dhe minus unar (-), modulin (%) dhe caktimin (=).

Operatorët përdoren për të marrë një vlerë të re nga vlerat që operohen. Këto vlera fillestare quhen operandët. Rezultati i operacionit duhet të ruhet në memorie. Ndonjëherë ai ruhet në një variabël që përmban një nga operandët origjinalë. Përpiluesi C # gjeneron një mesazh gabimi nëse një vlerë e re nuk përcaktohet ose ruhet kur përdoret një operator. Kodi më poshtë nuk i ndryshon vlerat. Përpiluesi do të lëshojë një mesazh gabimi sepse një shprehje aritmetike që nuk ndryshon të paktën një vlerë zakonisht konsiderohet gabim.

klasa NoResultApp

{

zbrazëti publike statike kryesore ()

{

int i; int j;

i + j; // Gabim sepse rezultati nuk është caktuar për asgjë. )>

Shumica e operatorëve punojnë vetëm me lloje të të dhënave numerike si p.sh Byte, Short, Long, Integer, Single, Double dhe dhjetore. Një përjashtim janë operatorët e krahasimit (== dhe! =). Gjithashtu, në C #, mund të përdorni operatorët + dhe - për klasën Varg dhe madje përdorni operatorët e rritjes (++) dhe (-) për konstruksione të pazakonta gjuhësore si delegatët. Unë do të flas për këtë të fundit në kapitullin 14.

Vjetërsia e operatorit

Kur ka disa deklarata në një shprehje, përpiluesi duhet të përcaktojë rendin e ekzekutimit të tyre. Në këtë rast, përpiluesi udhëhiqet nga rregullat e quajtura vjetërsia e operatorëve. Kuptimi i përparësisë së operatorëve është i nevojshëm për drejtshkrimi i saktë shprehjet - ndonjëherë rezultati mund të mos jetë siç pritej.

Konsideroni shprehjen 42 + 6 * 10. Nëse shtoni 42 dhe 6, dhe pastaj shumëzoni shumën me 10, merrni 480. Nëse shumëzoni 6 me 10 dhe shtoni 42 në rezultat, merrni 102. Kur përpiloni kodin, një komponent i veçantë përpilues është - analizues leksikor -është përgjegjës për radhën në të cilën lexohet ky kod. Është analizuesi leksikor ai që përcakton përparësinë relative të operatorëve heterogjenë në një shprehje. Për ta bërë këtë, ai përdor një vlerë - prioritetin - të secilit operator të mbështetur. Së pari lejohen operatorët me prioritet më të lartë. Në shembullin tonë, operatori * ka përparësi ndaj operatorit +, pasi * thith(tani do ta shpjegoj këtë term) operandët e mi përpara + e bën atë. Shpjegimi qëndron në rregullat e përgjithshme të aritmetikës: shumëzimi dhe pjesëtimi. gjithmonë kanë përparësi ndaj mbledhjes dhe zbritjes. Le të kthehemi te shembulli: ata thonë se numri 6 i gëlltitur operatori * në të dy 42 + 6 * 10 dhe 42 * 6 + 10, kështu që këto shprehje janë ekuivalente me 42 + (6 * 10) dhe (42 * 6) + 10.

Si përcaktohet vjetërsia në C #

Tani le të shohim se si përcaktohet përparësia e operatorit në C #. Operatorët janë renditur më poshtë në rend zbritës të përparësisë (Tabela 10-1). Do të hyj në më shumë detaje mbi kategoritë e ndryshme të operatorëve të mbështetur në C # më vonë.

Tab. 10-1. Përparësia e operatorit në C #.

Kategoria e operatorit Operatorët
E thjeshtë (x), xy, f (x), a [x], x ++, x -, e re, lloji, madhësia, e kontrolluar, e pakontrolluar
Unar +, -,!, ++ x, - x, (T) x
Shumëzues *,/, %
Shtues +, -
Zhvendosja «, »
Qëndrimi <, >, <=, >=, është
Barazia ==
Logjike DHE (DHE) &
Ekskluzive logjik OSE (XOR) ^
OSE logjike (OR) 1
E kushtëzuar DHE &&
IL e kushtëzuar DHE (OR) II
gjendja 9-
Detyra = *= /= % = , + = , -= « = , » = , &=, ^ = , =

Asociacioni majtas dhe djathtas

Asociativiteti përcakton se cila pjesë e shprehjes duhet të vlerësohet së pari. Për shembull, rezultati i shprehjes së mësipërme mund të jetë 21 ose 33, në varësi të cilit asociativitet do të përdoret për operatorin "-": majtas ose djathtas.

Operatori - ka asociativitetin e majtë, dmth fillimisht llogaritet 42-15, dhe rezultatit i zbritet 6. Nëse do të kishte asociativitetin e duhur, fillimisht do të llogaritet ana e djathtë e shprehjes (15-6), e më pas rezultati. do të zbritej nga 42.

Të gjithë operatorët binarë (operatorët me dy operandë), përveç operatorëve të caktimit, - majtas-asociative, dmth përpunojnë shprehjet nga e majta në të djathtë. Në këtë mënyrë, a + b+ Me - e njejte si (a + b) + c, ku llogaritet fillimisht a + b, dhe më pas shtohet shuma Me. Operatorët e caktimit dhe deklarata të kushtëzuara - asociative e djathte, dmth përpunojnë shprehjet nga e djathta në të majtë. Me fjale te tjera, a = b = c ekuivalente me a = (b= Me). Shumë njerëz pengohen me këtë kur duan të vendosin disa deklarata detyrash në një rresht, kështu që le të shohim këtë kod:

duke përdorur Sistemin;

klasa RightAssocApp (

zbrazëti publike statike kryesore () (

int a = 1; int b = 2; int c = 3;

Console.WriteLine ("a = (0) b = (1) c = (2>", a, b, c); a = b = c;

Console.WriteLine ("Pas" a = b = c -: a = (0) b = (1) c = (2) ", a, b, c);>>

Rezultati i ekzekutimit të këtij shembulli është si më poshtë:

a = 1 b = 2 c = 3

Pas "a = b = c": a = 3 b = 3 o = 3

Vlerësimi i shprehjeve nga e djathta në të majtë mund të jetë konfuze në fillim, por le t'i qasemi në këtë mënyrë: nëse operatori i detyrës do të lihej asociativ, përpiluesi fillimisht do të duhej të vlerësonte a = b, pastaj a do të ishte e barabartë me 2 dhe më pas b= s dhe si rezultat b do të ishte 3. Rezultati përfundimtar do të ishte a = 2 b = 3 c = 3. Natyrisht, kjo nuk është ajo që presim kur shkruajmë a= b= me, dhe për këtë arsye operatorët e caktimit dhe të kushtëzuar janë të drejtë-shoqërues.

Përdorimi praktik

Asgjë nuk është më e mundimshme sesa gjetja e një gabimi të bërë vetëm sepse zhvilluesi nuk i njihte rregullat e përparësisë dhe të shoqërimit. Kam hasur në mesazhe në konferencat me postë, në të cilat njerëz në dukje të arsyeshëm propozojnë një lloj mekanizmi vetëdokumentues - përdorimin e hapësirave për t'u treguar operatorëve që, sipas mendimit të tyre, kanë vjetërsi pune. Për shembull, meqenëse e dimë se operatori i shumëzimit ka përparësi ndaj operatorit të mbledhjes, duhet të shkruajmë diçka të tillë, në të cilën hapësirat tregojnë të nënkuptuara vjetërsia:

a = b * c + d;

Kjo qasje është thelbësisht e gabuar: përpiluesi nuk mund të analizojë saktë kodin nëse sintaksa specifike nuk është përcaktuar. Përpiluesi analizon kodin sipas rregullave të përcaktuara nga zhvilluesit e përpiluesit. Nga ana tjetër, ka kllapa të rrumbullakëta përdoret për të treguar në mënyrë eksplicite përparësinë dhe asociativitetin. Për shembull, shprehja a= b * c + d mund të rishkruhet si a = (b * c) + d ose si a= b * (c + d) dhe kompajleri së pari do të vlerësojë shprehjen e vendosur në kllapa. Nëse ka çifte të shumta kllapash, përpiluesi së pari do të vlerësojë shprehjet e vendosura në kllapa, dhe më pas të gjithë shprehjen, bazuar në rregullat e përparësisë dhe asociativitetit të përshkruara.

Unë jam i bindur se kllapat duhet të përdoren gjithmonë kur ka shumë operatorë në një shprehje. Unë rekomandoj ta bëni këtë edhe nëse e kuptoni rendin e llogaritjeve, sepse njerëzit që do të ruajnë kodin tuaj mund të mos jenë aq të shkolluar.

Operatorët C #

Është më e sakta të merren parasysh operatorët sipas vjetërsisë. Më poshtë do të përshkruaj operatorët më të zakonshëm.

Operatorë të thjeshtë

  • (x) Ky është një variacion i operatorit të kllapave për të kontrolluar rendin e vlerësimit si në operacionet matematikore dhe kur thirrni metoda.
  • xy Operatori i pikës përdoret për të treguar një anëtar të një klase ose strukture. Këtu X përfaqëson një ent që përmban një anëtar në.
  • f (x) Ky lloj operatori i kllapave përdoret për të renditur argumentet e metodës.
  • Oh] Kllapa katrore përdoren për të indeksuar një grup. Këto kllapa përdoren gjithashtu në lidhje me indeksuesit kur objektet mund të trajtohen si një grup. Për indeksuesit, shihni kapitullin 7.
  • х ++ Për operatorin e rritjes do të flasim veçmas në seksionin "Operatorët e rritjes dhe zvogëlimit".
  • x- Operatori i zvogëlimit do të diskutohet më vonë.
  • i ri Ky operator përdoret për të instancuar objektet bazuar në një përkufizim të klasës.

lloji i

Reflektimi(refleksioni) është aftësia për të marrë informacionin e tipit në kohën e ekzekutimit. Ky informacion përfshin emrat e llojeve, klasave dhe anëtarëve të strukturës. V. NET Framework ky funksionalitet lidhet me klasën Sistemi. Lloji. Kjo klasë është rrënja e të gjithë operatorëve të reflektimit dhe mund të merret duke përdorur operatorin lloji i. Ne nuk do të hyjmë në detajet e reflektimit tani (ne do ta bëjmë këtë në Kapitullin 16), por këtu është një shembull i thjeshtë për të ilustruar se sa e lehtë është përdorimi i operatorit lloji i"për të marrë pothuajse çdo informacion rreth një lloji ose objekti gjatë ekzekutimit të programit:

duke përdorur Sistemin;

duke përdorur System.Reflection;

klasë publike Apple (

publike int nSeeds;

boshllëku publik Ripen ()

{

> >

klasa publike TypeOfApp (

zbrazëti publike statike kryesore () (

Lloji t = lloji (Mollë);

emri i klasës së vargut = t.ToStringO;

Console.IgShip ("\ nInformacion 0 class (O)", classEmri);

Console.WriteLine ("\ nMeroflH (0)", Emri i klasës); Konsolë. WriteLine ("--------"); Metodat Methodlnfo = t.GetMethodsO;

foreach (metoda MethodInfo në metoda)

Console.WriteLine (metoda.Zalja ToSt ());

}

Console.WriteLine ("\ nBce anëtarë (O)", Emri i klasës); Konsolë. Writel_ine ("--------"); Anëtarëso të gjithëAnëtarët = t.Merr AnëtarëO; foreach (Anëtar i Memberlnfo në të gjithë Anëtarët)

{

Konsolë. WriteLine (anëtar.ToStringO);

} > }

Ky program përmban klasën Apple i cili ka vetëm dy anëtarë: fushë nFarat dhe metodë Pjekur. Së pari, duke përdorur operatorin lloji i dhe emrin e klasës e marr objektin Sistemi. Lloji, e cila më pas ruhet në një variabël t. ME në këtë pikë unë mund të përdor objektin Sistemi. Lloji për të marrë të gjitha metodat dhe anëtarët e një klase Apple. Kjo bëhet duke përdorur metodat GetMethods dhe GetAnëtarë përkatësisht. Rezultatet e këtyre metodave shfaqen në pajisje standarde dalje si më poshtë:

Informacion rreth Klasa e mollës Metodat e Apple

Int32 GetHashCodeQ

Sistemi.String ToStringQ

E zbrazët RipenO

Sistemi.Type GetTypeO

Të gjithë anëtarët e Apple

Int32 nFarat

Int32 GetHashCodeO

Boolean Equals (System.Object)

Sistemi.String ToStringO

E zbrazët RipenO

Sistemi.Type GetTypeO

Para se të vazhdoj më tej, dua të them dy pika. Së pari, vini re se anëtarët e trashëguar të klasës janë konstatuar gjithashtu. Meqenëse klasa nuk rrjedh në mënyrë eksplicite nga një klasë tjetër, ne e dimë se të gjithë anëtarët nuk janë përcaktuar në klasë Apple trashëgojnë nga klasa bazë e nënkuptuar Sistemi.Objekt. Së dyti, objekti Sistemi.Lloji mund të merret me metodë GetType. Kjo është e trashëguar nga Sistemi.Objekt metoda ju lejon të punoni me objekte, jo me klasa. Çdo nga dy fragmentet e mëposhtme mund të përdoret për të marrë një objekt Sistemi. Lloji.

II Marrja e një objekti System.Type bazuar në përkufizimin e klasës. Lloji t1 = lloji (Mollë);

// Merrni objektin System.Type nga objekti. Mollë mollë= AppleQ i ri; Lloji t2 = mollë.GetTypeO;

madhësia e

Operatori madhësia e përdoret për të marrë madhësinë e llojit të specifikuar në bajt. Në të njëjtën kohë, mbani mend rreth dy ekskluzivisht faktorë të rëndësishëm... Së pari, madhësia e mund të aplikohet vetëm për llojet dimensionale. Prandaj, ndërsa mund të përdoret për anëtarët e klasës, nuk mund të përdoret për klasa si të tilla. Së dyti, madhësia e mund të përdoret vetëm në metoda ose blloqe kodesh të shënuara si e pasigurt. ME Me këtë lloj kodi do të njihemi në kapitullin 17. Këtu është një shembull i përdorimit të operatorit madhësia e në një metodë të një klase të shënuar si i pasigurt:

duke përdorur Sistemin;

klasat BasicTypes (

// Shënim: Kodi që përdor operatorin sizeof // duhet të shënohet si i pasigurt, publik i pasigurt statik i pavlefshëm ShowSizesQ (

Console.WriteLine ("\ nPa3Mephi llojet kryesore"); Console.WriteLine ("Pa3Mep i shkurtër = (0)", sizeof (i shkurtër)); Console.WriteLine ("Pa3Mep int = (0)", sizeof (int)); Console.Writel_ine ("Pa3Mep i gjatë = (0)", sizeof (i gjatë)); Console.WriteLine ("Pa3Mep bool = (0)", sizeof (bool)); ))

klasa UnsafeUpp

{

boshllëk statik publik i pasigurt MainQ

{

BasicTypes.ShowSizes ();

} }

Këtu është rezultati nga ky aplikacion:

Madhësitë e llojeve bazë Madhësia e shkurtër = 2 Madhësia int = 4 Madhësia e gjatë = 8 Madhësia bool = 1

Operatori madhësia e mund të përdoret për të përcaktuar dimensionet jo vetëm për llojet e thjeshta të integruara, por edhe për llojet e dimensioneve të personalizuara si strukturat. Megjithatë, rezultatet madhësia e mund të mos jetë e qartë:

// Përdorimi i operatorit sizeof. duke përdorur Sistemin;

Struktura StructWithNoMembers

struct StructWithMembers

{

Pantallona të shkurtra;

int i;

e gjatë 1;

bool b; )

struct CompositeStruct

{

StrukturaMeNoAnëtarë a; StructWithAnëtarë b;

StrukturaMeNoAnëtarë c; )

Klasa UnSafe2App (

boshllëk i pasigurt publik statik Kryesor () (Console.WriteLine ("\ nPa3Mep StructWithNoMembers strukturë = (0)",

sizeof (StructWithNoMembers)); Console.WriteLine ("\ nPa3Mep StructWithMembers struktura = (0)",

sizeof (StructWithMembers)); Console.WriteLine ("\ nPa3Mep CompositeStruct Struktura = (0)",

sizeof (CompositeStruct)); ))

Edhe pse mund të supozohet se ky aplikacion do të nxjerrë 0 për një strukturë pa anëtarë (StructWithNo Members), 15 për një strukturë me katër anëtarë të llojeve bazë (StructWithAnëtarë) dhe 15 për një strukturë që bashkon dy të mëparshmet (CompositeStruct), në realitet rezultati do të jetë si ky:

Struktura Size StructWithNoMembers = 1 Size StructWithMembers Struktura = 16

Madhësia e strukturës së përbërë = 24

Shpjegimi për këtë është mënyra për të mbajtur konstruktin struktura kompajleri në skedarin dalës ku përpiluesi aplikon justifikimin dhe mbushjen. Për shembull, nëse një strukturë është 3 bajt në madhësi dhe e rreshtuar në kufijtë 4 bajt, përpiluesi automatikisht do t'i shtojë strukturës 1 bajt dhe operatori madhësia e do të tregojë se madhësia e strukturës është 4 bajt. Mos harroni ta mbani parasysh këtë kur përcaktoni madhësinë e strukturave në C #.

kontrolluar dhe i pakontrolluar

Këta dy operatorë kontrollojnë kontrollin e tejmbushjes kur kryejnë veprime matematikore.

Operatorët e matematikës

C #, si shumica e gjuhëve të tjera, mbështet operatorët bazë matematikorë: shumëzimin (*), pjesëtimin (/), mbledhjen (+), zbritjen (-) dhe modulin (%). Qëllimi i katër operatorëve të parë është i qartë nga emrat e tyre; operatori i modulit formon pjesën e mbetur të një ndarjeje të numrit të plotë. Ja disa kode për të ilustruar përdorimin e operatorëve matematikorë:

duke përdorur Sistemin;

klasa MathOpsApp

{

zbrazëti publike statike MainQ

{

// Klasa System.Random është pjesë e bibliotekës së klasës // .NET Framework. Në konstruktorin e saj të paracaktuar, // metoda Next përdor datën / kohën aktuale si // vlera fillestare... Random Random = i ri RandomO; int a, b, c;

a = rand. Tjetra () % njeqind; // Vlera kufitare 99. b = rand.NextO % 100; // Vlera kufitare 99.

Console.WriteLine ("a = (0) b = (1)", a, b);

c = a * b;

Console.WriteLineC "a * b = (0)", c);

// Vini re se numrat e plotë përdoren këtu. // Prandaj, nëse a është më pak se b, rezultati do të jetë gjithmonë // 0. Për të marrë një rezultat më të saktë // duhet të përdorni variablat si dyfishtë ose noton, c = a / b; Console.WriteLineC "a / b = (0)", c);

Console.WriteLineC "a + b = (0)", c);

Console.WriteLineC "a - b = (0)", c);

Console.WriteLineC "a X b = (0)", c); >>

Operatorët Unarë

Ekzistojnë dy operatorë unarë: plus dhe minus. Operatori unar minus i tregon kompajlerit se numri është negativ. Pra në kodin e mëposhtëm a do të jetë e barabartë me -42:

duke përdorur Sistemin; duke përdorur Sistemin;

klasa UnarylApp (

zbrazëti publike statike kryesore ()

{

int a = 0;

a = -42;

Console.WriteLine ("(0)", a); ))

Megjithatë, paqartësia shfaqet në këtë kod: duke përdorur Sistemin;

Klasa Unary2App<

zbrazëti publike statike kryesore () (

int a; int b = 2; int c = 42;

a = b * -c;

Console.WriteLine ("(0)", a); >>

Shprehje a= b * -c jo mjaft e qartë. Përsëri, përdorimi i kllapave do të qartësojë këtë shprehje:

// Kur përdorim kllapa, është e qartë se po // shumëzojmë b me një numër negativ c. a = b * (-c);

Nëse kthehet minus unary kuptim negativ operand, mund të mendohet se një plus unar do të kthehej pozitiv. Megjithatë, plus unary vetëm e kthen operandin në formën e tij origjinale dhe nuk bën asgjë tjetër, domethënë nuk ndikon në operand. Për shembull, ekzekutimi i këtij kodi do të nxjerrë vlerën -84:

duke përdorur Sistemin;

klasa UnarySapp (

zbrazëti publike statike MainQ (

a = b * (+ c);

Console.WriteLine ("(0)", a); ))

Për të marrë një vlerë pozitive, përdorni funksionin Math.Abs. Ky kod do të printojë vlerën 84:

duke përdorur Sistemin;

Klasa Unary4App

{

zbrazëti publike statike kryesore ()

int a; int b = 2; int c = -42;

a = b * Math.Abs ​​(c); Console.Writel_ine ("(0)", a); ))

Operatori i fundit unar që përmenda është T (x). Ky është një variant i operatorit të kllapave që ju lejon të transmetoni nga një lloj në tjetrin. Meqenëse mund të mbingarkohet duke krijuar një transformim të personalizuar, ne do ta diskutojmë atë në Kapitullin 13.

Operatorët e Përbërjes së Përbërjes

Operatori i caktimit të kompleksit -është një kombinim i operatorit binar dhe operatorit të caktimit (=). Sintaksa për këta operatorë është si më poshtë:

kor = y

ku op - ky është operatori. Vini re se kur e bëni këtë, vlera e majtë (lvlera) nuk zëvendësohet me të drejtën (rvlera), një deklaratë e përbërë ka të njëjtin efekt si:

x = x op

dhe lvlera përdoret si bazë për rezultatin e operacionit.

Vini re që thashë "ka të njëjtin efekt". Përpiluesi nuk përkthen një shprehje si x + = 5 inç X= x + 5, ai vepron logjikisht. ME vëmendje të veçantë duhet t'i referoheni rasteve kur lvleraështë një metodë. Merrni parasysh kodin:

duke përdorur Sistemin;

klasa CompoundAssignmentlApp (

elemente lnt të mbrojtura;

në publik GetArrayElementO

{

elementet e kthimit;

}

CompoundAssignment1App () (

elemente = int e re;

elemente = 42;

}

zbrazëti publike statike kryesore () (

Aplikacioni CompoundAssignmentlApp = i ri CompoundAsslgnment1App ();

Console.WrlteLine ("(0>", app.GetArrayElement ());

app.GetArrayElement () = app.GetArrayElement () + 5; Console.WriteLine ("(0)", app.GetArrayElement ()); ). )

Vini re thirrjen e theksuar të linjës - metodë Compound-AssignmentlApp.GetArrayElement dhe më pas duke ndryshuar elementin e parë - këtu kam përdorur sintaksën:

x = x op

Kështu do të gjenerohet kodi MSIL: // Teknika joefektive: x = x op y.

Metoda publike hldebyslg static void Kryesor () 11 i menaxhuar

Entrypolnt

// Madhësia e kodit 79 (Ox4f) .maxstack 4

Lokale (klasa CompoundAssignmentlApp V_0)

IL_0000: instancë e re e pavlefshme CompoundAssignmentlApp ::. Ctor () IL_0005: stloc.O IL_0006: Idstr "(OG IL_OOOb: ldloc.0 ILJJOOc: shembulli i thirrjes int32

CompoundAssignmentlApp :: GetArrayElementO

IL_0011: ldc.14.0

IL_0012: Idelema ["mscorlib"] System.Int32

IL_0017: kutia [1 mscorlib "] System.Int32

IL_001c: thirrja e pavlefshme ["mscorlib 1] System.Console :: WriteLine (klasa System.String, klasa System.Object)

IL_0021: ldloc.0

IL_0022: shembulli i thirrjes int32 CompoundAssignmentlApp :: GetArrayElementO

IL_0027: Idc.i4.0

IL_0028: ldloc.0

IL_0029: shembulli i thirrjes int32 CompoundAssignmentlApp:: GetArrayElementO

IL_002e: Idc.i4.0

IL_002f: ldelem.14

IL_0030: ldc.14.5

IL_0031: shtoni

IL_0032: stelem.14

IL_0033: Idstr "(0)"

IL_0038: ldloc.0

IL_0039: telefononi

shembull int32 CompoundAssignmentlApp :: GetArrayElement () IL_003e: ldc.14.0

IL_003f: Idelema ["mscorlib"] Systera.Int32 IL_0044: kutia ["msoorlib"] System.Int32 IL_0049: thirrja e pavlefshme ["mscorlib"] System. Konsol :: WriteLine

(klasa System.String, klasa System.Object) IL_004e: ret

) // fundi i metodës "CompoundAssignmentlApp :: Main"!

Shikoni linjat e ndërthurura: metodë CompoundAssignmentlApp.Get-ArrayElement në fakt quhet dy herë! Kjo është e paefektshme, për të thënë më së paku, dhe ndoshta e dëmshme në varësi të asaj që bën metoda tjetër.

Tani le të shohim një kod tjetër që përdor sintaksën e operatorit të caktimit të përbërë:

duke përdorur Sistemin;

Klasa CompoundAssignment2App (

elemente int të mbrojtura;

në publik GetArrayElementO

elementet e kthimit;

}

CompoundAssignment2App () (

elemente = int e re;

elemente = 42;

}

zbrazëti publike statike kryesore () (

Aplikacioni CompoundAssignment2App = aplikacioni i ri CompoundAssignment2App ();

Console.WriteLine ("(0)", app.GetArrayElement ());

app.GetArrayElement () + = 5; Console.WriteLine ("(0)", app.GetArrayElement ()); ))

Përdorimi i operatorit të caktimit të përbërë do të rezultojë në një kod MSIL shumë më efikas:

// Teknika më efikase: x op = y.

Metoda publike hidebysig static void Kryesor () il menaxhuar

\ {

\ .pikë hyrëse

I // Madhësia e kodit 76 (Ox4c) \ .maxstack 4

Locals (klasa CompoundAssignmentlApp V_0, int32 V_1) \ IL_0000: shembulli i ri i pavlefshëm CompoundAssignmentlApp ::. Ctor () \ IL_0005: stloc.O 1 IL_0006: Idstr "(0)" 1 IL_OOOb: ldloc.0 IL_OOOc: shembulli i thirrjes int32

CompoundAssignmentlApp :: GetArrayElementO IL_0011: Idc.i4.0

IL_0012: Idelema [mscorlib "] System.Int32 IL_0017: box [> mscorlib -] System.Int32 lL_001c: call void [" mscorlib "] System.Console :: WriteLine

(klasa System.String, klasa System.Object) IL_0021: ldloc.0 IL_0022: shembulli i thirrjes int32

CompoundAssignmentlApp :: GetArrayElement ()

IL_0027: dup

IL_0028: stloc.1

IL_0029: Idc.i4.0

IL_002a: ldloc.1

IL_002b: Idc.i4.0

IL_002c: ldelem.14

IL_002d: ldc.14.5

IL_002e: shtoni

IL_002f: stelem.14

IL_0030: Idstr "(0)"

IL_0035: ldloc.0

IL_0036: shembulli i thirrjes int32

CompoundAssignmentlApp :: GetArrayElementO IL_003b: Idc.i4.0

IL_003c: Idelema ["mscorlib"] System.Int32

IL_0041: kutia [mscorlib "] System.Int32

IL_0046: call void ["mscorlib"] System.Console :: WriteLine

(klasa System.String, klasa System.Object)

IL_004b: ret) // fundi i metodës "CompoundAssignmentlApp :: Main"

Ju mund të shihni komandën MSIL të përdorur dup. Ai kopjon artikullin kryesor në pirg, duke krijuar kështu një kopje të vlerës së kthyer nga metoda CompoundAssignmentlApp.Get Element Array. Unë

Kjo tregon se edhe pse në thelb x + = y ekuivalente me x = x + y, Kodi MSIL është i ndryshëm në të dyja rastet. Ky dallim duhet t'ju bëjë të pyesni veten se cila sintaksë të përdorni në secilin rast. Një rregull i madh dhe rekomandimi im është që të përdoren operatorët e caktimit të përbërë kurdo dhe kudo që të jetë e mundur.

Operatorët e rritjes dhe zvogëlimit

U prezantua në C dhe u transferua në C ++ dhe Operatorët Java rritja 1 dhe zvogëlimi ju lejojnë të shprehni në mënyrë koncize se dëshironi të rritni ose ulni një vlerë numerike me 1. Kjo do të thotë, / ++ është e barabartë me shtimin e 1 në vlerën aktuale të / ".

Prania e dy formave të operatorëve të rritjes dhe zvogëlimit ndonjëherë është konfuze. Parashtesa dhe postfiks llojet e këtyre operatorëve ndryshojnë në momentin në të cilin ndryshohet vlera. Në versionin prefiks të operatorëve të rritjes dhe zvogëlimit (++ ai - a përkatësisht) fillimisht kryhet operacioni dhe më pas krijohet vlera. Në versionin postfix (a ++ dhe a-) fillimisht krijohet vlera dhe më pas kryhet operacioni. Le të shqyrtojmë një shembull:

duke përdorur Sistemin;

klasa IncDecApp (

boshllëk publik statik Foo (int j)

{

Console.WriteLine ("IncDecApp.Foo j = (0)", j);

>

zbrazëti publike statike kryesore () (

int i = 1;

Console.WriteLineC "flo thërret në Foo (i ++) = (0)", i);

Console.WriteLine ("Pas thirrjes së Foo (i ++) = (0)", i);

Console.WriteLine ("\ n");

\ Console.WriteLineC "flo thërret në Foo (++ i) = (0)", i);

\ Foo (++ l);

\ Console.WrlteLine ("Pas thirrjes së Foo (++ i) = (0)", i);

l Rezultati do të duket si ky:

Përpara se të telefononi Foo (i ++) = 1

IncDecApp.Foo j = 1

Pasi të telefononi Foo (i ++) = 2

Përpara se të telefononi Foo (-n-i) = 2

IncDecApp.Foo j = 3

Pasi të telefononi Foo (++ i) = 3

Dallimi është kur krijohet vlera dhe modifikohet operandi. Kur telefononi Foo (i ++) vlera / "i kalohet (e pandryshuar) metodës Foo dhe pas kthimi i metodës / rritet me 1. Shikoni kodin e mësipërm MSIL: komandën shtoni ekzekutohet pasi vlera të shtyhet në pirg.

IL.0013: ldloc.0

IL.0014: dup

IL_0015: Idc.i4.1

IL_0016: shtoni

IL_0017: stloc.O

IL_0018: thirrje e pavlefshme IncDecApp :: Foo (int32)

Tani le të shohim formën e operatorit prefiks të përdorur në thirrje Foo (++ a). Në këtë rast, kodi MSIL do të jetë i ndryshëm. Në këtë rast, komanda shtoni kryer përpara si shtyhet vlera në pirg për thirrjen e mëvonshme të metodës Foo.

IL.0049: ldloc.0

IL_004a: Idc.i4.1

IL_004b: shtoni

IL_004c: dup

IL_004d: stloc.O

IL_004e: thirrje e pavlefshme IncDecApp :: Foo (int32)

Operatorët relacionalë

Shumica e operatorëve kthejnë vlera numerike. Sa për operatorët relacionalë, ata gjenerojnë një rezultat boolean. Në vend të / në vend të kryerjes së operacioneve matematikore në një grup operandësh, / operatorët relacionalë analizojnë marrëdhëniet midis operandëve dhe kthimi kuptimi e vertete, nëse raporti është i vërtetë, i rremë - nëse / është e rreme.

Operatorët e Krahasimit

Te operatorët relacionalë të thirrur operatorët e krahasimit, referoj) -është "më pak" (<), «меньше или равно» (<=), «больше» (>), Më e madhe se ose e barabartë (> =), E barabartë (==), dhe Jo e barabartë (! =). Zbatimi i këtyre operatorëve në numra është i kuptueshëm, por kur përdoren me objekte, zbatimi i tyre nuk është aq i dukshëm. Ja një shembull:

duke përdorur Sistemin;

klasa Numeric Test (

NumericTest publik (int 1)

{

kjo.i = i;

>

i mbrojtur int 1; )

klasa RelationalOpslApp (

zbrazëti publike statike kryesore () (

NumericTest testl = NumericTest i ri (42); NumericTest test2 = NumericTest i ri (42);

Console.WriteLine ("(0)", testl == test2); >)

Nëse jeni një programues Java, ju e dini se çfarë do të ndodhë këtu. Sidoqoftë, programuesit e C ++ me shumë mundësi do të befasohen kur shohin rezultatin i rremë. Më lejoni t'ju kujtoj se kur krijoni një shembull të një objekti, ju merrni një lidhje me të. Kjo do të thotë që kur ndeshet me një operator relacioni që krahason dy objekte, përpiluesi C # nuk krahason përmbajtjen e objekteve, por adresat e tyre. Për ta kuptuar më mirë këtë, merrni parasysh kodin MSIL:

\ .metoda publike hldebysig statike void MainQ il menaxhuar

\ .pikë hyrëse

\ // Madhësia e kodit 39 (0x27)

1 .maxstack 3

Vendasit (klasa NumericTest V_0, \ klasa NumericTest V_1, 1 bool V_2)

ILJJOOO: Idc.i4.s 42

1L_0002: shembulli i ri i pavlefshëm NumericTest ::. Ctor (int32)

IL_0007: stloc.O

IL_0008: Idc.i4.s 42

IL_OOOa: shembulli i ri i pavlefshëm NumericTest ::. Ctor (int32)

IL_OOO nga: stloc.1

IL_0010: Idstr "(0)"

IL_0015: ldloc.0

IL_0016: ldloc.1

IL_0017: eeq

IL_0019: stloc.2

IL_001a: Idloca.s V_2

IL_001c: box ["mscorlib"] System.Boolean

IL_0021: thirrja e pavlefshme ["mscorlib"] System.Console :: WriteLine

(klasa System.String, klasa System.Object)

IL_0026: ret) // fundi i metodës "RelationalOpslApp :: Main"

Shikoni vijën .vendasit. Përpiluesi tregon se metoda Kryesor tre variabla lokale. Dy të parat janë objekte Testi numerik, një e treta është një variabël boolean. Tani le të kalojmë te linjat IL_0002 dhe IL_0007. Kjo është ajo ku objekti është instancuar testl, dhe lidheni me të me stloc ruhet në variablin e parë lokal. Megjithatë, është e rëndësishme që MSIL të ruajë adresën e objektit të krijuar rishtazi. Pastaj në rreshta IL_OOOa dhe IL_OOO e ju shihni kodet MSIL për krijimin e objekteve testi 2 dhe ruajtja e referencës së kthyer në një variabël të dytë lokale. Më në fund, në rreshta 1LJ) 015 dhe IL_0016 variablat lokale shtyhen në rafte nga komanda Idloc, dhe në linjë IL_0017 ekipi gri krahason dy vlerat në krye të pirgut (d.m.th., referencat e objekteve testl dhe testl). Vlera e kthyer ruhet në variablin e tretë lokal dhe më pas shfaqet sipas metodës Sistemi.Konsol. WriteLine.

Por si i krahasoni anëtarët e dy objekteve? Përgjigja është përdorimi i klasës bazë të nënkuptuar të të gjithë objekteve .NET Framework. Gjegjësisht, për këto qëllime, klasa Sistemi.Objekt ka një metodë Të barabartë. Për shembull, kodi i mëposhtëm krahason përmbajtjen e objekteve dhe daljeve, siç do të prisnit, e vërtetë: Unë

duke përdorur Sistemin; /

Klasa RelationalOps2App

(/ zbrazëti publike statike kryesore () (

Console.WriteLine ("(0)", testl.Equals (test2));

Shembulli RelationalOpslApp përdor një klasë "homemade". (Nu-mericTest) dhe në shembullin e dytë - klasa .NET (dhjetore).Çështja është se metoda Sistemi.Objekti.E barabartë duhet të anashkalohet për të bërë krahasimin e vërtetë të anëtarëve. Prandaj metoda Të barabartë me klasën Testi numerik nuk do të funksionojë sepse ne nuk e kemi anashkaluar metodën. Dhe këtu është klasa dhjetore anashkalon metodën që trashëgon Të barabartë, dhe në këtë rast gjithçka do të funksionojë.

Një mënyrë tjetër për të krahasuar objektet është përdorimi mbingarkesa e operatorit(mbingarkimi i operatorit). Mbingarkimi i operatorit përcakton operacionet e kryera në objekte të një lloji të caktuar. Për shembull, për objektet varg operatori + nuk kryen mbledhje, por përkundrazi bashkon vargjet. Ne do të mbulojmë mbingarkimin e operatorit në Kapitullin 13.

Operatorë të thjeshtë të caktimit

Vlera në anën e majtë të operatorit të caktimit thirret lvlera, dhe në anën e djathtë - rvlera. Si rvlera mund të jetë çdo konstante, ndryshore, numër ose shprehje, rezultati i së cilës është i pajtueshëm lvlera. ndërkohë lvlera duhet të jetë një variabël i një lloji specifik. Çështja është se vlera kopjohet nga ana e djathtë në të majtë. Kështu, një hapësirë ​​fizike adresash duhet të ndahet për vlerën e re. Për shembull, mund të shkruani / "= 4, meqenëse ka vend për / në memorie - ose në pirg ose në grumbull - në varësi të llojit të /. Dhe këtu është operatori 4 = 1 nuk mund të ekzekutohet sepse 4 është një vlerë, jo një variabël, përmbajtja e së cilës në memorie mund të ndryshohet. Nga rruga, unë do të vërej se në C # si lvlera mund të jetë një variabël, veti ose indeksues. Për më shumë informacion mbi vetitë dhe indeksuesit, shihni Kapitullin 7. Në këtë kapitull, unë përdor variabla për thjeshtësi. Nëse me detyrë vlerat numerike gjithçka është mjaft e qartë, me objektet është më e ndërlikuar. Më lejoni t'ju kujtoj se kur keni të bëni me objekte, ju po manipuloni sende që nuk grumbullohen dhe janë të lehta për t'u kopjuar dhe lëvizur. Në rastin e objekteve, ju në të vërtetë keni vetëm referenca për disa nga entitetet për të cilat memorja ndahet në mënyrë dinamike. Prandaj, kur përpiqeni t'i caktoni një objekt (ose ndonjë lloj referimi) një ndryshoreje, të dhënat nuk kopjohen, siç është rasti me llojet dimensionale, por referencat.

Le të themi se keni dy objekte: testl dhe testi 2. Nëse specifikoni testl= test2, testl nuk do të jetë një kopje testi 2. Ata do të përputhen! Nje objekt testl tregon për të njëjtën kujtesë si testi 2, dhe çdo ndryshim në objekt testl do të çojë në ndryshime testi 2. Këtu është një program që ilustron këtë:

duke përdorur Sistemin;

klasa Foo (

publike int i; )

klasa RefTestlApp (

boshllëk publik statik MainO (

Foo testl = Foo e re (); testl.i = 1;

Foo test2 = Foo i ri (); test2.i = 2;

Console.WriteLine ("Para caktimit të objekteve"); Console.WriteLine ("test1.i = (0>", testl.i); Console.WriteLine ("test2.i = (0)", test2.i); Console.WriteLine ("\ n");

testl = test2;

Console.Writel_ine ("Pas caktimit të objekteve");

Console.WriteLine ("test1.i = (0)", testl.i); Console.WriteLine ("test2.i = (0)", test2.i); Console.WriteLine ("\ n");

testl.i = 42; ;"

Console.WriteLine ("Pas ndryshimit të vetëm anëtarit TEST1"); Console.WriteLine ("test1.i = (0)", testl.i); Console.WriteLine ("test2.i = (0)", test2.i); Console.WriteLine ("\ n"); ))

Duke ekzekutuar këtë kod, do të shihni:

Para caktimit të një objekti

testi1.i = 1

test2.i = 2

Pas caktimit të një objekti

testt.i = 2

test2.i = 2

Pas ndryshimit të vetëm anëtari TEST1

testi1.i = 42

test2.i = 42

Le të shohim se çfarë ndodh në secilën fazë të këtij shembulli. Foo -është një klasë e thjeshtë k me vetëm një anëtar, /. Në metodën Main, krijohen dy instanca të kësaj klase: testl dhe testi 2- dhe anëtarët e tyre i janë vendosur respektivisht në 1 dhe 2. Këto vlera më pas nxirren, dhe siç pritej testl.iështë e barabartë me 1, a test2.i- 2. Dhe këtu fillon argëtimi! V rreshti tjetër Objekt testl caktuar testi 2. Lexuesit e Java-s e dinë se çfarë është më pas. Sidoqoftë, shumica e programuesve C ++ do të presin një anëtar / objekt testl tani është e barabartë me një anëtar të objektit testi 2(duke supozuar se kur të kompilohet një aplikacion i tillë, do të ekzekutohet një lloj operatori për të kopjuar anëtarët e objektit). Rezultati i shfaqur duket se e konfirmon këtë. Sidoqoftë, në realitet, lidhja midis objekteve tani është shumë më e thellë. Cakto vlerën 42 anëtarit testl.i dhe printoni sërish rezultatin. DHE?! Kur objekti ndryshon testl ndryshuar dhe testZ Kjo ka ndodhur për faktin se objekti testl jo më. Pas caktimit të tij testi 2 nje objekt testl humbet sepse nuk referohet më nga aplikacioni dhe si rrjedhojë “pastrohet” nga mbledhësi i plehrave (GC). Tani testl dhe testi 2 tregoni të njëjtën kujtesë në grumbull. Prandaj, kur një variabël ndryshon, përdoruesi do të shohë edhe ndryshimin tjetër.

Vini re dy rreshtat e fundit që po shtypen: megjithëse vetëm vlera ka ndryshuar në kod testl.i, kuptimi test2.i gjithashtu ndryshoi. Edhe një herë, të dy variablat tregojnë tani në të njëjtin vend memorie - kjo është sjellja që programuesit Java do të prisnin. Sidoqoftë, kjo nuk i plotëson aspak pritshmëritë e zhvilluesve të C ++, pasi është kopjimi i objekteve që kryhet në këtë gjuhë: secila variabël ka kopjen e saj unike të anëtarëve të saj dhe ndryshimet në një objekt nuk ndikojnë në tjetrin. Meqenëse ky është çelësi për të kuptuar se si funksionojnë objektet në C #, le të anashkalojmë pak dhe të shohim se çfarë ndodh kur i kaloni një objekt një metode:

duke përdorur Sistemin;

klasa Foo (

publike int i; )

Klasa RefTest2App (

publik void ChangeValue (Foo f)

{

f.i = 42;

}

zbrazëti publike statike kryesore () (

Aplikacioni RefTest2App = i ri RefTest2App ();

Foo test = Foo i ri (); test.i = 6;

Console.WriteLine ("Para thirrjes së metodës"); Console.WriteLine ("test.i = (0)", test.i); Console.WriteLine ("\ n");

app.ChangeValue (test);

Console.WriteLine ("Pas thirrjes së metodës"); Console.WriteLine ("test.i = (0)", test.i); Console.WriteLine ("\ n"); >)

Në shumicën e gjuhëve përveç Java, ky kod do të kopjojë objektin e krijuar test në steka e metodave lokale RefTest2App.ChangeValue. Në këtë rast, objekti test, krijuar në metodë Kryesor, nuk do të shohë kurrë ndryshime në / objekt të bëra në metodë Ndryshimi Vlera. Megjithatë, e përsëris edhe një herë se metoda Kryesor kalon një referencë për një objekt të caktuar nga grumbulli provë. Kur metoda Ndryshimi i vlerës manipulon variablin e saj lokal //, ai gjithashtu manipulon drejtpërdrejt objektin provë metodë Kryesor.

Le të përmbledhim

Gjëja kryesore në çdo gjuhë programimi është mënyra për të kryer detyrat, operacionet matematikore, logjike dhe të marrëdhënieve - gjithçka që kërkohet për të punuar. aplikacione reale... Në kod, këto operacione përfaqësohen nga operatorët. Faktorët që ndikojnë në ekzekutimin e operatorëve përfshijnë përparësinë dhe asociativitetin (djathtas dhe majtas) të operatorëve. Grupi i fuqishëm i operatorëve të paracaktuar në C # mund të zgjerohet me implementime të përcaktuara nga përdoruesi, për të cilat do të flasim në Kapitullin 13.

Përditësimi i fundit: 19.06.2017

Shprehjet e kushtëzuara janë një grup i veçantë operacionesh. Operacione të tilla kthejnë një vlerë boolean, domethënë një vlerë të tipit bool: true nëse shprehja është e vërtetë dhe false nëse shprehja është false. Operacione të tilla përfshijnë operacione krahasimi dhe logjike.

Operacionet e krahasimit

Operacionet e krahasimit krahasojnë dy operandë dhe kthejnë një vlerë bool - true nëse shprehja është e vërtetë dhe false nëse shprehja është false.

    Krahason dy operandë për barazi. Nëse ato janë të barabarta, atëherë operacioni kthehet true, nëse nuk janë të barabartë, atëherë kthehet false:

    B; // i rremë

    Krahason dy operandë dhe kthen true nëse operandët nuk janë të barabartë, dhe false nëse janë të barabartë.

    Int a = 10; int b = 4; bool c = a! = b; // bool i vërtetë d = a! = 10; // i rremë

    Më pak se operacioni. Rikthen true nëse operandi i parë është më i vogël se i dyti dhe false nëse operandi i parë është më i madh se i dyti:

    Int a = 10; int b = 4; bool c = a< b; // false

    Më e madhe se operacioni. Krahason dy operandë dhe kthen true nëse operandi i parë është më i madh se i dyti, përndryshe kthen false:

    Int a = 10; int b = 4; bool c = a> b; // bool i vërtetë d = a> 25; // i rremë

    Më pak se ose e barabartë me funksionimin. Krahason dy operandë dhe kthen true nëse operandi i parë është më i vogël ose i barabartë me i dyti. Përndryshe kthehet false.

    Int a = 10; int b = 4; bool c = a<= b; // false bool d = a <= 25; // true

    Më e madhe se ose e barabartë me funksionimin. Krahason dy operandë dhe kthen true nëse operandi i parë është më i madh ose i barabartë me të dytin, përndryshe kthen false:

    Int a = 10; int b = 4; bool c = a> = b; // bool i vërtetë d = a> = 25; // i rremë

Operacionet<, > <=, >= ka përparësi mbi == dhe! =.

Operacionet logjike

C # gjithashtu përcakton operatorët logjikë që kthejnë gjithashtu një vlerë bool. Ata marrin vlerat bool si operandë. Zakonisht aplikohen në marrëdhënie, ato kombinojnë operacione të shumta krahasimi.

    Shtim logjik ose OSE logjik. Kthen true nëse të paktën një nga operandët kthehet true.

    Bool x1 = (5> 6) | (4< 6); // 5 >6 - e rreme, 4< 6 - true, поэтому возвращается true bool x2 = (5 >6) | (4> 6); // 5> 6 - e rreme, 4>

    Shumëzimi logjik ose operacioni logjik DHE Rikthen true nëse të dy operandët janë njëkohësisht të vërtetë.

    Bool x1 = (5> 6) & (4< 6); // 5 >6 - e rreme, 4< 6 - true, поэтому возвращается false bool x2 = (5 < 6) & (4 < 6); // 5 < 6 - true, 4 < 6 - true, поэтому возвращается true

    Operacioni i shtimit logjik. Kthen true nëse të paktën një nga operandët kthehet true.

    Bool x1 = (5> 6) || (4< 6); // 5 >6 - e rreme, 4< 6 - true, поэтому возвращается true bool x2 = (5 >6) || (4> 6); // 5> 6 është false, 4> 6 ​​është false, pra false kthehet

    Operacioni logjik i shumëzimit. Rikthen true nëse të dy operandët janë njëkohësisht true.

    Bool x1 = (5> 6) && (4< 6); // 5 >6 - e rreme, 4< 6 - true, поэтому возвращается false bool x2 = (5 < 6) && (4 < 6); // 5 < 6 - true, 4 >6 është e vërtetë, pra e vërteta është kthyer

    Operacioni i mohimit logjik. Ai kryhet në një operand dhe kthehet true nëse operandi është false. Nëse operandi është i vërtetë, atëherë operacioni kthehet false:

    Bool a = e vërtetë; bool b =!a; // i rremë

    Operacioni ekskluziv OSE. Rikthen true nëse operandi i parë ose i dyti (por jo të dy) janë true, përndryshe kthen false

    Bool x5 = (5> 6) ^ (4< 6); // 5 >6 - e rreme, 4< 6 - true, поэтому возвращается true bool x6 = (50 > 6) ^ (4 / 2 < 3); // 50 >6 - e vërtetë, 4/2< 3 - true, поэтому возвращается false

Këtu kemi dy palë operacionesh | dhe || (si dhe & dhe &&) bëjnë gjëra të ngjashme, por ato nuk janë të njëjta.

Në shprehjen z = x | y; do të llogariten edhe x edhe y.

Në shprehjen z = x || y; së pari, do të llogaritet vlera e x, dhe nëse është e vërtetë, atëherë llogaritja e vlerës së y nuk ka më kuptim, pasi në çdo rast, z tashmë do të jetë e barabartë me e vërtetë. Y do të llogaritet vetëm nëse x është false

E njëjta gjë vlen edhe për çiftin & / && të operacioneve. Shprehja z = x do të vlerësojë edhe x edhe y.

Në shprehjen z = x &, vlera x do të llogaritet së pari, dhe nëse është e gabuar, atëherë llogaritja e vlerës y nuk ka më kuptim, pasi në rastin tonë, në çdo rast, z tashmë do të jetë e barabartë me false. . Y do të llogaritet vetëm nëse x është e vërtetë

Prandaj, operacionet || dhe && janë më të përshtatshme në llogaritje, pasi ju lejojnë të zvogëloni kohën për vlerësimin e vlerës së një shprehjeje dhe në këtë mënyrë të rrisni performancën. Dhe operacionet | dhe & janë më të përshtatshme për kryerjen e operacioneve në bit në numra.

Operatori && ka përparësi ndaj operatorit ||. Pra, në shprehjen e vërtetë || true && false, nënshprehja true && false ekzekutohet së pari.

Artikujt kryesorë të lidhur