Kako podesiti pametne telefone i računare. Informativni portal

C-sharp operateri. Uslovni izrazi

Posljednje ažuriranje: 19.06.2017

C# koristi većinu operacija koje se koriste u drugim programskim jezicima. Operacije predstavljaju određene radnje nad operandima - učesnicima operacije. Operand može biti varijabla ili neka vrijednost (na primjer, broj). Operacije su unarne (izvode se na jednom operandu), binarne - na dva operanda i ternarne - na tri operanda. Razmotrite sve vrste operacija.

Binarne aritmetičke operacije:

    Operacija sabiranja dva broja:

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

    Operacija oduzimanja dva broja:

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

    Operacija množenja dva broja:

    int x = 10; int z = x * 5; // pedeset

    operacija dijeljenja dva broja:

    int x = 10; int z = x / 5; // 2 duplo a = 10; duplo b = 3; duplo c = a / b; // 3.33333333

    Prilikom dijeljenja, imajte na umu da ako oba operanda predstavljaju cijele brojeve, onda će i rezultat biti zaokružen na cijeli broj:

    Dvostruki z = 10 / 4; //rezultat je 2

    Iako se rezultat operacije na kraju stavlja u varijablu tip double, što vam omogućava da uštedite frakcijski dio, ali sama operacija uključuje dva literala, koji se po defaultu tretiraju kao int objekti, odnosno cijeli brojevi, a rezultat će također biti cijeli broj.

    Da biste izašli iz ove situacije, potrebno je definirati literale ili varijable uključene u operaciju točno kao tipove double ili float:

    Dvostruki z = 10,0 / 4,0; //rezultat je 2.5

    Operacija za primanje bilansa iz cjelobrojna podjela dva broja:

    dupli x = 10,0; duplo z = x % 4,0; //rezultat je 2

Postoji i broj unarne operacije, u kojem učestvuje jedan operand:

    operacija inkrementa

    Povećanje može imati prefiks: ++x - prvo se vrijednost x povećava za 1, a zatim se njegova vrijednost vraća kao rezultat operacije.

    Tu je i postfiksni inkrement: x++ - prvo se vrijednost x vraća kao rezultat operacije, a zatim joj se dodaje 1.

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

Operacija za smanjenje ili smanjenje vrijednosti za jedan. Postoji i prefiksni oblik dekrementa (--x) i postfiksni oblik (x--).

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

Prilikom izvođenja nekoliko aritmetičkih operacija odjednom, treba uzeti u obzir redoslijed njihovog izvršenja. Prioritet operacija od najvišeg do najnižeg:

    povećanje, smanjenje

    Množenje, dijeljenje, ostatak

    Sabiranje, oduzimanje

Zagrade se koriste za promjenu redoslijeda operacija.

Razmotrite skup operacija:

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)");

Ovdje imamo posla sa tri operacije: dekrementiranje, oduzimanje i množenje. Prvo se dekrementira varijabla c, zatim množenje b*a i na kraju oduzimanje. To jest, u stvari, skup operacija izgledao je ovako:

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

Ali sa zagradama, mogli bismo promijeniti redoslijed operacija, na primjer, na sljedeći način:

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)");

Asocijativnost operatora

Kao što je gore navedeno, operacije množenja i dijeljenja imaju isti prioritet, ali šta će onda biti rezultat u izrazu:

int x = 10 / 5 * 2;

Da li ovaj izraz treba tumačiti kao (10 / 5) * 2 ili kao 10 / (5 * 2)? Uostalom, u zavisnosti od interpretacije, dobijamo različite rezultate.

Kada operacije imaju isti prioritet, redoslijed evaluacije je određen asocijativnošću operatora. Ovisno o asocijativnosti, postoje dvije vrste operatora:

    Lijevi asocijativni operatori koji se izvršavaju s lijeva na desno

    Desno asocijativni operatori koji se izvršavaju s desna na lijevo

Sve aritmetički operatori(osim inkrementa i dekrementa prefiksa) su lijevo asocijativni, odnosno izvršavaju se s lijeva na desno. Stoga se izraz 10 / 5 * 2 mora tumačiti kao (10 / 5) * 2, odnosno rezultat će biti 4.

Relacioni operatori i logički operatori

U notaciji operator relacije i logički operator termin odnosi znači odnos koji može postojati između dva značenja i pojma logicno- odnos između logičkih vrijednosti "tačno" i "netočno". A budući da relacijski operatori daju istinite ili lažne rezultate, često se koriste u sprezi s logičkim operatorima. Iz tog razloga se smatraju zajedno.

Ovo su relacioni operatori:

Booleovi operatori uključuju sljedeće:

Rezultat izvršavanja relacionog ili logičkog operatora je booleova vrijednost tipa bool.

Općenito, objekti se mogu porediti za jednakost ili nejednakost koristeći relacijske operatore == i !=. A operatori poređenja, =, mogu se primijeniti samo na tipove podataka koji podržavaju odnos poretka. Stoga se relacijski operatori mogu primijeniti na sve numeričke tipove podataka. Ali bool vrijednosti se mogu porediti samo za jednakost ili nejednakost, jer istinite (tačne) i lažne (netačne) vrijednosti nisu poređane. Na primjer, poređenje true > false u C# nema smisla.

Razmotrimo primjer programa koji pokazuje upotrebu relacijskih i logičkih operatora:

Korišćenje sistema; koristeći System.Collections.Generic; koristeći System.Linq; koristeći System.Text; imenski prostor ConsoleApplication1 ( klasa Program ( static void Main(string args) (kratko d = 10, f = 12; bool var1 = true, var2 = false; if (d f) Console.WriteLine("d > f"); // Poređenje varijable var1 i var2 if (var1 & var2) Console.WriteLine("Ovaj tekst neće biti izlaz"); if (!(var1 & var2)) Console.WriteLine("!(var1 & var2) = true"); if (var1 | var2) Console.WriteLine("var1 | var2 = true"); if (var1 ^ var2) Console.WriteLine("var1 ^ var2 = true"); Console.ReadLine(); ) ) )

Logički operatori u C#-u izvode najčešće logičke operacije. Ipak, postoji niz operacija koje se izvode prema pravilima formalne logike. Ove logičke operacije se mogu izgraditi pomoću logičkih operatora podržanih u C#. Stoga C# pruža skup logičkih operatora koji je dovoljan za konstruiranje gotovo svake logičke operacije, uključujući implikaciju. implikacija je binarna operacija koja se procjenjuje na false samo ako je njen lijevi operand istinska vrijednost, a desna je lažna. (Operacija implikacije odražava princip da istina ne može implicirati netačno.)

Operacija implikacije može se izgraditi na osnovu kombinacije logičkih operatora! i |:

Prečica Boolean operatori

C# takođe pruža posebne skraćeno, varijante logičkih AND i OR operatora dizajniranih za proizvodnju efikasnijeg koda. Objasnimo ovo u slijedećim primjerima logičke operacije. Ako je prvi operand logičke I operacije lažan, tada će njegov rezultat biti lažan, bez obzira na vrijednost drugog operanda. Ako je prvi operand logičke operacije ILI istinit, tada će njegov rezultat biti istinit bez obzira na vrijednost drugog operanda. Zbog činjenice da vrijednost drugog operanda u ovim operacijama nije potrebno izračunavati, štedi vrijeme i poboljšava efikasnost koda.

Skraćena logička I operacija se izvodi pomoću operater &&, i skraćena logička operacija ILI - korištenje operater ||. Ovi skraćeni logički operatori odgovaraju regularnim logičkim operatorima & i |. Jedina razlika između skraćenog logičkog operatora i regularnog je u tome što se njegov drugi operand procjenjuje samo prema potrebi.

U jeziku C# ne postoje implicitne konverzije u boolean tip, čak ni za cijele brojeve. aritmetički tipovi. Stoga je potpuno ispravan unos u jeziku C++:

intk1 = 7;
ako (k1) Konzola. Write Line(" uredu!");

nezakonito u C# programima. Doći će do greške tokom koraka prevođenja jer je procijenjeno stanje tipa int, i implicitna konverzija ovog tipa u tip bool je odsutan.

U C#, stroža pravila važe i za logičke operacije. Da, zapis ako(k1 && (x> y)), ispravno u C++, dovodi do greške u

C# programe jer je && operator definiran samo za operande tipa bool, i u ovom izrazu jedan od operanada ima tip int. U jeziku C#, u ovim situacijama, trebali biste koristiti notaciju:

ako(k1>0)
ako((k1>0) && (x> y))

Logičke operacije se dijele u dvije kategorije: neke se izvode na booleovim vrijednostima operanada, druge izvode logičku operaciju nad bitovima operanada. Iz tog razloga, postoje dvije unarne negacije u C# - logička negacija, specificirana pomoću "!" operatora, i negacija po bitu, specificirana pomoću "~" operatora. Prvi je definiran preko operanda tipa bool, drugi - preko operanda cjelobrojnog tipa, počevši od tipa int i više (int, uint, dugo, ulong). Rezultat operacije u drugom slučaju je operand u kojem je svaki bit zamijenjen svojim komplementom. Evo primjera:

/// < sažetak>
/// Bulovi izrazi
/// sažetak>
javnostivoidlogika() {
// operacije negacije ~, !
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);
} // logika

Ovaj fragment komentariše izjave koje vode do grešaka. U prvom slučaju, pokušano je primijeniti operaciju negacije po bitu na izraz tipa bool, u drugom, logička negacija je primijenjena na cjelobrojne podatke. Oba su ilegalna u C#. Obratite pažnju na različitu interpretaciju negacije po bitu za neoznačene i predpisane tipove cijelih brojeva. Za varijable j5 i j2 bitni niz koji daje vrijednost je isti, ali se različito tumači. Relevantan izlaz je:

uintj2 = 4294967288
intj5 = -8.

Binarne logičke operacije" && - kondicional I "i" || - uslovno ILI" su definirani samo preko tipa podataka bool. Operacije se nazivaju uslovne ili kratke jer evaluacija drugog operanda zavisi od već procenjene vrednosti prvog operanda. Vrijednost uslovnih Booleovih operacija leži u njihovoj efikasnosti u vremenu izvršenja. Često vam omogućavaju da izračunate boolean izraz A to ima smisla, ali gdje drugi operand nije definiran. Uzmimo kao primjer klasični problem pretraživanja po uzorku u nizu, kada se traži element sa datom vrijednošću (uzorkom). Takav element u nizu može ili ne mora postojati. Evo tipičnog rješenja ovog problema u pojednostavljenom obliku, ali koje prenosi suštinu stvari:

// UslovnoI- &&
int[] ar= { 1, 2, 3 };
int search= 7;
int i= 0;
dok ((i< ar.Length)&& (ar[i]!= traži)){
i++;
}
ako ja< ar.Length)Console.WriteLine("Uzorakpronađeno");
ostaloConsole.WriteLine("Uzoraknepronađeno");

Ako je vrijednost varijable traži(uzorak) ne odgovara nijednoj vrijednosti elementa niza ar, zatim posljednji test stanja petlje dokće se izvršiti sa vrijednošću i, jednak ar. Dužina. U ovom slučaju, prvi operand će dobiti vrijednost false, i iako drugi operand nije definiran, petlja će normalno izaći. Drugi operand nije definiran u zadnja provjera, jer je indeks elementa niza izvan opsega (u C#, indeksiranje elemenata počinje od nule).

Tri binarne bitne operacije- «& - I» , « | - OR", "^ - XOR" se koriste na dva načina. Definirani su kao gore navedeni cjelobrojni tipovi int, i preko Booleovih tipova. U prvom slučaju koriste se kao bitne operacije, u drugom se koriste kao obične logičke operacije. Ponekad je neophodno da se oba operanda ipak procene, tada su ove operacije neophodne. Evo primjera njihove prve upotrebe:

//Logičke operacije u bitovimaI, Or, 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);

Izlazni rezultati:

k4 = 5 k5 = 7 k6 =2

Evo primjera uparivanja uzoraka pomoću logičkog I: i= 0;

traži= ar;
dok ((i< ar.Length)& (ar[i]!= traži)) i++;
ako ja< ar.Length)Console.WriteLine("Uzorakpronađeno");
ostalo cConsole.WriteLine("Uzoraknepronađeno");

Ovaj isječak zagarantirano ima obrazac traženja u nizu i isječak će se uspješno pokrenuti. U istim slučajevima kada niz ne sadrži element traži, bit će izbačen izuzetak. Smisleno značenje takvog postupka - pojava izuzetka - može biti znak greške u podacima, što zahtijeva posebno postupanje sa situacijom.

POGLAVLJE 10 Izrazi i operatori

U ovom poglavlju ćemo se osvrnuti na osnove bilo kojeg programskog jezika – njegovu sposobnost obavljanja zadataka i poređenja pomoću operatora. Vidjet ćemo koji su operatori u C#-u i koji je njihov prioritet, a zatim ćemo se upustiti u pojedinačne kategorije izraza za izvođenje aritmetičkih operacija, dodjelu vrijednosti i poređenje operanada.

Operateri

Operator je simbol koji označava operaciju koja se izvodi na jednom ili više argumenata. Kada se naredba izvrši, dobije se rezultat. Sintaksa za primenu operatora je donekle drugačija od pozivanja metoda i trebalo bi da znate format izraza koji sadrže operatore u C# kao svoj džep. Kao iu većini drugih jezika, semantika operatora u C# prati pravila i notacije koje su nam poznate iz škole. Osnovni operateri u C# uključuju množenje (*), dijeljenje (/), sabiranje i unarni plus (+), oduzimanje i unarni minus (-), modul (%) i dodjeljivanje (=).

Operatori se koriste za dobivanje nove vrijednosti iz vrijednosti na kojima se operacija izvodi. Ove početne vrijednosti se nazivaju operandi. Rezultat operacije mora biti pohranjen u memoriji. Ponekad se pohranjuje u varijablu koja sadrži jedan od originalnih operanada. C# kompajler generiše poruku o grešci ako nova vrijednost nije definirana ili pohranjena kada se koristi operator. Kod ispod ne mijenja vrijednosti. Kompajler će izdati poruku o grešci, jer se aritmetički izraz koji ne mijenja barem jednu vrijednost obično smatra greškom.

klasa NoResultApp

{

public static void Main()

{

int i; int j;

i+j; // Greška jer rezultat nije dodijeljen ničemu. ) >

Većina operatora radi samo na numeričkim tipovima podataka, kao što su Byte, Short, Long, Integer, Single, Double i Decimala. Izuzetak su operatori poređenja (== i !=). Takođe, u C#, možete koristiti + i - operatore na klasi String pa čak i koristiti operatore inkrementa (++) i (-) za takve neobične jezičke konstrukcije kao što su delegati. O ovom poslednjem ću govoriti u 14. poglavlju.

Prioritet operatera

Kada postoji više naredbi u istom izrazu, prevodilac mora odrediti redosled kojim se oni izvršavaju. Pri tome se prevodilac rukovodi pravilima tzv prioritet operatora. Razumijevanje prioriteta operatera je od suštinskog značaja za ispravan pravopis izrazi - ponekad rezultat možda neće biti očekivan.

Uzmite u obzir izraz 42 + 6 * 10. Ako dodate 42 i 6, a zatim pomnožite zbir sa 10, dobit ćete 480. Ako pomnožite 6 sa 10 i rezultatu dodate 42, dobit ćete 102. Prilikom kompajliranja koda, posebna komponenta kompajlera je leksički analizator - je odgovoran za redosled čitanja ovog koda. Leksički analizator je taj koji određuje relativni prioritet heterogenih operatora u jednom izrazu. Da bi to učinio, koristi neku vrijednost - prioritet - svakog podržanog operatora. Operatori višeg prioriteta se prvo rješavaju. U našem primjeru, * operator ima prednost nad + operatorom jer * upija(Sada ću objasniti ovaj termin) njegovi operandi prije + to radi. Objašnjenje leži u općim aritmetičkim pravilima: množenju i dijeljenju uvijek imaju veći prioritet od sabiranja i oduzimanja. Vratimo se na primjer: kažu da je broj 6 apsorbuje operator * i u 42 + 6 * 10 i u 42 * 6 + 10, tako da su ovi izrazi ekvivalentni 42 + (6 * 10) i (42 * 6) + 10.

Kako se određuje prioritet u C#

Sada da vidimo kako je prioritet operatora definisan u C#. Operateri su navedeni u nastavku u opadajućem redoslijedu prioriteta (Tabela 10-1). Zatim ću detaljnije opisati različite kategorije operatora podržanih u C#.

Tab. 10-1. Prioritet operatora u C#.

Kategorija operatera Operateri
Jednostavno (x), x.y, f(x), a[x], x++, x - , novo, typeof, sizeof, označeno, neoznačeno
unarno + , -, !, ++x, - x, (T)x
Multiplikativno *,/, %
aditiva +, -
Shift «, »
Stav <, >, <=, >=, je
Jednakost ==
Logično I (I) &
Logički isključivi OR (XOR) ^
logičko ILI (ILI) 1
Uslovno I (I) &&
Uslovni IL I (ILI) II
Stanje 9-
Zadatak = *= /= % = , + = , -= « = , » = , &=, ^ = , =

Lijeva i desna asocijativnost

Asocijativnost određuje koji dio izraza treba prvo procijeniti. Na primjer, rezultat gornjeg izraza može biti 21 ili 33, ovisno o tome koja će se asocijativnost primijeniti na operator "-": lijevo ili desno.

Operator - je lijevo asocijativan, tj. prvo se izračuna 42-15, a zatim se od rezultata oduzima 6. Da ima desnu asocijativnost, prvo bi se procijenila desna strana izraza (15-6), a zatim rezultat bi se oduzeo od 42.

Svi binarni operatori (operatori sa dva operanda), osim operatora dodjeljivanja, - lijevo-asocijativno, tj. obrađuju izraze s lijeva na desno. dakle, a + b+ sa - isto kao (a + b) + c, gdje se prvo računa a + b, a zatim dodato na zbir sa. operatori dodjeljivanja i uslovne izjave - desno-asocijativno, odnosno obrađuju izraze s desna na lijevo. Drugim riječima, a=b=c ekvivalentno a = (b= sa). Mnogi ljudi naiđu na ovo kada žele staviti više naredbi o dodjeli u isti red, pa pogledajmo ovaj kod:

korištenje sistema;

klasa RightAssocApp(

public static void Main() (

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("Nakon "a=b=c - : a=(0) b=(1) c=(2)", a, b, c); > >

Rezultat pokretanja ovog primjera je:

a=1 b=2 c=3

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

Evaluacija izraza s desna na lijevo u početku može biti zbunjujuća, ali pristupimo tome na ovaj način: da je operator dodjeljivanja lijevo asocijativan, kompajler bi prvo morao procijeniti a = b, onda a bi bilo 2 i onda b= sa i kao rezultat b bilo bi 3. Krajnji rezultat bi bio a=2 b=3 c=3. Očigledno, ovo nije ono što očekujemo kada pišemo a= b= sa, i zato su operatori dodjeljivanja i uvjetni operatori desno-asocijativni.

Praktična upotreba

Ništa nije tako problematično kao pronalaženje greške koja je napravljena samo zato što programer nije znao pravila prioriteta i asocijativnosti. Naišao sam na objave na mail konferencijama gdje su naizgled razumni ljudi predložili neku vrstu mehanizma samodokumentiranja - korištenje razmaka za navođenje operatera koji, po njihovom mišljenju, imati staž. Na primjer, pošto znamo da operator množenja ima prednost nad operatorom sabiranja, trebali bismo napisati nešto poput ovoga gdje razmaci označavaju implicirano staž:

a \u003d b * c + d;

Ovaj pristup je u osnovi pogrešan: kompajler ne može ispravno raščlaniti kod ako specifična sintaksa nije definirana. Kompajler analizira kod prema pravilima definisanim od strane programera kompajlera. S druge strane, postoje okrugle zagrade, koji se koristi za eksplicitno označavanje prioriteta i asocijativnosti. Na primjer, izraz a= b * c + d može se prepisati kao a \u003d (b * c) + d ili kako a= b * (c + d) a kompajler će prvo procijeniti izraz u zagradama. Ako postoji više parova zagrada, kompajler će prvo procijeniti izraze u zagradama, a zatim cijeli izraz, na osnovu opisanih pravila prioriteta i asocijativnosti.

Čvrsto vjerujem da zagrade uvijek treba koristiti kada postoji više operatora u izrazu. Preporučujem da to učinite čak i ako razumijete redoslijed izračunavanja, jer ljudi koji će održavati vaš kod možda neće biti toliko pismeni.

C# operatori

Najbolje je posmatrati operatore prema prioritetu. U nastavku ću opisati najčešće operatore.

Jednostavni operateri

  • (x) Ovo je neka vrsta operatora zagrade za kontrolu redoslijeda evaluacije kao u matematičke operacije, i prilikom pozivanja metoda.
  • x.y Operator točka se koristi za specificiranje člana klase ili strukture. Evo X predstavlja entitet koji sadrži člana y.
  • f(x) Ova vrsta operatora zagrade se koristi za nabrajanje argumenata metoda.
  • Oh] Uglaste zagrade se koriste za indeksiranje niza. Ove zagrade se takođe koriste zajedno sa indekserima kada se objekti mogu tretirati kao niz. Pogledajte Poglavlje 7 za indeksere.
  • x++ O operatoru inkrementa ćemo govoriti posebno u odjeljku “Operatori povećanja i dekrementa”.
  • x- O operatoru dekrementa ćemo takođe govoriti kasnije.
  • new Ovaj operator se koristi za kreiranje instanci objekta na osnovu definicije klase.

vrstu

Refleksija(refleksija) je mogućnost dobivanja informacija o tipu u vrijeme izvođenja. Ove informacije uključuju imena tipova, klasa i članova strukture. AT. NET Framework ova funkcionalnost je povezana sa klasom Sistem. tip. Ova klasa je korijen svih operatora refleksije i može se dobiti pomoću operatora vrstu. Nećemo sada ulaziti u detalje refleksije (doći ćemo do toga u poglavlju 16), ali evo jednostavnog primjera koji ilustrira koliko je lako koristiti vrstu"da biste dobili gotovo sve informacije o tipu ili objektu u vrijeme izvođenja:

korištenje sistema;

koristeći System.Reflection;

javna klasa jabuka(

public int nSeeds;

javna praznina Ripen()

{

> >

javna klasa TypeOfApp(

public static void Main() (

Typet = typeof(Apple);

string className = t.ToStringO;

Console.IgShipe("\nInformacije o klasi 0 (O)", ime klase);

Console.WriteLine("\nMeroflH (0)", className); konzola. WriteLine("-------"); MethodInfo metode = t.GetMethodsO;

foreach (metoda MethodInfo u metodama)

Console.WriteLine(method.ToString());

}

Console.WriteLine("\nBce članovi (O)", className); konzola. Writel_ine("-------"); MemberInfo allMembers = t.GetMembersO; foreach (MemberInfo član u svim članovima)

{

konzola. WriteLine(member.ToStringO);

} > }

Ovaj program sadrži klasu jabuka, koja ima samo dva člana: polje nSeeds i metod Ripen. Prvo, korištenjem operatora vrstu i ime klase, dobijam objekat Sistem. tip, koji se zatim pohranjuje u varijablu t. With sada mogu koristiti objekat Sistem. tip da dobijete sve metode i članove klase Apple. Ovo se radi pomoću metoda GetMethods i GetMembers respektivno. Rezultati ovih metoda su prikazani na standardni uređaj izlaz ovako:

Informacije o Klasa jabuka Apple metode

Int32 GetHashCodeQ

System.String ToStringQ

Void RipenO

System.Type GetTypeO

Svi članovi Apple-a

Int32 nSeeds

Int32 GetHashCodeO

Boolean jednako (System.Object)

System.StringToStringO

Void RipenO

System.Type GetTypeO

Pre nego što nastavim, želim da dam dve napomene. Prvo, primijetite da su naslijeđeni članovi klase također zaključeni. Pošto klasa nije eksplicitno izvedena iz druge klase, znamo da svi članovi nisu definisani u klasi Apple naslijeđen od implicitne osnovne klase System.Object. Drugo, objekat System.Type može se dobiti metodom Gettype. Ovo je naslijeđeno od System.Object metoda vam omogućava da radite sa objektima, a ne klasama. Bilo koji od sljedeća dva isječka se može koristiti za dobivanje objekta Sistem. tip.

II Nabavite System.Type objekt baziran na definiciji klase. Typet1 = typeof(Apple);

// Dobivamo objekt System.Type iz objekta. jabuka jabuka= novi AppleQ; Tip t2 = apple.GetTypeO;

sizeof

Operater sizeof koristi se za dobivanje veličine navedenog tipa u bajtovima. Istovremeno, zapamtite isključivo dva važni faktori. Kao prvo, sizeof može se primijeniti samo na tipove dimenzija. Stoga, iako se može koristiti za članove klase, ne može se koristiti za klase kao takve. drugo, sizeof može se koristiti samo u metodama ili blokovima koda označenim kao nesigurno. With videćemo ovu vrstu koda u poglavlju 17. Evo primera korišćenja operatora sizeof u metodi klase označenom kao nesigurno:

korištenje sistema;

klasa BasicTypes(

// Napomena: Kod koji koristi operator sizeof // mora biti označen kao nesiguran, statički nesiguran public void ShowSizesQ (

Console.WriteLine("\nPa3Mephi osnovni tipovi"); Console.WriteLine("Pa3Mep kratko = (0)", sizeof(short)); Console.WriteLine("Pa3Mep int = (0)", sizeof(int)); Console.Writel_ine("Pa3Mep long = (0)", sizeof(long)); Console.WriteLine("Pa3Mep bool = (0)", sizeof(bool)); ) )

class UnsafeUpp

{

nesigurna javna statička void Main()

{

BasicTypes.ShowSizes();

} }

Evo rezultata pokretanja ove aplikacije:

Veličine osnovnih tipova Veličina kratka = 2 Veličina int = 4 Veličina duga = 8 Veličina bool = 1

Operater sizeof može se koristiti za definiranje dimenzija ne samo za jednostavne ugrađene tipove, već i za prilagođene tipove dimenzija kao što su strukture. Međutim, dok rezultati sizeof možda nije očigledno:

// Korištenje operatora sizeof. korištenje sistema;

struct StructWithNoMembers

struct StructWithMembers

{

kratke hlače;

int i;

long1;

bool b; )

struct CompositeStruct

{

StructWithNoMembers a; StructWithMembersb;

StructWithNoMembers c; )

classUnSafe2App(

nesiguran javni statički void Main() ( Console.WriteLine("\nPa3Mep StructWithNoMembers struktura = (0)",

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

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

sizeof(CompositeStruct)); ) )

Iako se može pretpostaviti da će ova aplikacija ispisati 0 za strukturu bez članova (StructWithNoMembers), 15 za strukturu sa četiri člana osnovnog tipa (StructWithMembers) i 15 za strukturu koja objedinjuje dvije prethodne (kompozitna struktura), u stvarnosti rezultat će biti ovakav:

Veličina strukture StructWithMembers = 1 Veličina strukture StructWithMembers = 16

Veličina strukture CompositeStruct = 24

Objašnjenje za ovo je način na koji se konstrukt čuva struct od strane kompajlera u izlaznoj datoteci, u kojoj kompajler primenjuje poravnanje i padding. Na primjer, ako je struktura veličine 3 bajta i postavljeno je poravnanje od 4 bajta, kompajler će automatski dodati 1 bajt strukturi, a naredbu sizeof označava da je veličina strukture 4 bajta. Imajte to na umu kada dimenzionirate strukture u C#.

provjereno i neprovjereno

Ova dva operatora kontrolišu provjeru prelijevanja prilikom izvođenja matematičkih operacija.

Matematički operatori

C#, kao i većina drugih jezika, podržava osnovne matematičke operatore: množenje (*), dijeljenje (/), sabiranje (+), oduzimanje (-) i modul (%). Svrha prva četiri operatora je jasna iz njihovih imena; modulo operator formira ostatak celobrojnog dijeljenja. Evo koda koji ilustruje upotrebu matematičkih operatora:

korištenje sistema;

klasa MathOpsApp

{

public static void Main()

{

// Klasa System.Random je dio // biblioteke klasa .NET Framework. U svom zadanom konstruktoru // Next metoda koristi trenutni datum/vrijeme kao // početna vrijednost. Random Rand = novi RandomO; int a, b, c;

a = rand.Next() % 100; // Granična vrijednost 99. b = rand.NextO % 100; // granična vrijednost 99.

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

c = a * b;

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

// Imajte na umu da se ovdje koriste cijeli brojevi. // Stoga, ako je a manji od b, rezultat će // uvijek biti 0. Da biste dobili precizniji rezultat, // trebate koristiti varijable tipa dupli ili float, 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); > >

Unarni operatori

Postoje dva unarna operatora: plus i minus. Unarni minus operator govori kompajleru da je broj negativan. Dakle, u sljedećem kodu a biće jednako -42:

korištenje sistema; korištenje sistema;

klasa UnarylApp(

public static void Main()

{

int a = 0;

a = -42;

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

Međutim, ovaj kod uvodi dvosmislenost: korištenje sistema;

klasa Unary2App<

public static void Main() (

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

a = b * -c;

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

Izraz a= b*-c nije sasvim jasno. Opet, upotreba zagrada će pojasniti ovaj izraz:

// Kada koristite zagrade, očito je da // množimo b negativnim brojem c. a \u003d b * (-c);

Ako se vraća unarni minus negativno značenje operand, mogli biste pomisliti da bi unarni plus vratio pozitivno. Međutim, unarni plus samo vraća operand u njegovom originalnom obliku i ne radi ništa drugo, tj. ne utiče na operand. Na primjer, izvršavanje ovog koda će ispisati vrijednost -84:

korištenje sistema;

classUnarySapp(

javna statička praznina MainQ(

a = b * (+c);

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

Da biste dobili pozitivnu vrijednost, koristite funkciju Math Abs. Ovaj kod će ispisati vrijednost 84:

korištenje sistema;

klasa Unary4App

{

public static void Main()

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

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

Posljednji unarni operator koji sam spomenuo je T(x). Ovo je vrsta operatora zagrade koji vam omogućava da prebacujete jedan tip na drugi. Budući da se može preopteretiti kreiranjem prilagođene transformacije, raspravljat ćemo o tome u 13. poglavlju.

Složeni iskazi o dodjeli

Složeni operator dodjeljivanja - to je kombinacija binarnog operatora i operatora dodjele (=). Sintaksa za ove operatore je:

refren = y

gdje op - to je operater. Imajte na umu da je u ovom slučaju lijeva vrijednost (lvalue) nije zamijenjeno pravom (rvalue), složeni operator ima isti efekat kao:

x = x op at

i lvalue koristi se kao osnova za rezultat operacije.

Zapazite da sam rekao "ima isti efekat." Kompajler ne prevodi izraz kao što je x += 5 in X= x + 5, ponaša se logično. With posebnu pažnju treba uzeti u obzir kada lvalue je metoda. Uzmite u obzir kod:

korištenje sistema;

klasa CompoundAssignmentlApp(

zaštićeni lnt elementi;

public int GetArrayElementO

{

povratni elementi;

}

CompoundAssignment1App() (

elementi = novi int;

elemenata = 42;

}

public static void Main() (

CompoundAssignmentlApp app = nova CompoundAsslgnment1App();

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

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

Obratite pažnju na označenu liniju - poziv metode Compound-AssignmentlApp.GetArrayElement a zatim mijenjam prvi element - ovdje sam koristio sintaksu:

x = x op at

Ovo je MSIL kod koji će se generirati: // Neefikasna tehnika: x = x o y.

Metoda public hldebyslg static void Main() 11 upravlja

Entrypolnt

// Veličina koda 79 (Ox4f) .maxstack 4

Lokalni (klasa CompoundAssignmentlApp V_0)

IL_0000: newobj instanca void CompoundAssignmentlApp::.ctor() IL_0005: stloc.O IL_0006: Idstr "(OG IL_OOOb: ldloc.0 ILJJOOc: poziv instance int32

CompoundAssignmentlApp::GetArrayElementO

IL_0011: ldc.14.0

IL_0012: Idelema["mscorlib"]System.Int32

IL_0017: kutija [ 1 mscorlib"]System.Int32

IL_001c: call void ["mscorlib 1 ]System.Console::WriteLine (klasa System.String, klasa System.Object)

IL_0021: ldloc.0

IL_0022: poziv instance int32 CompoundAssignmentlApp::GetArrayElementO

IL_0027: Idc.i4.0

IL_0028: ldloc.0

IL_0029: poziv instance int32 CompoundAssignmentlApp: :GetArrayElementO

IL_002e: Idc.i4.0

IL_002f: ldelem.14

IL_0030: ldc.14.5

IL_0031: dodaj

IL_0032: čelik.14

IL_0033: Idstr "(0)"

IL_0038: ldloc.0

IL_0039: poziv

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

IL_003f: Idelema ["mscorlib"]Systera.Int32 IL_0044: box ["msoorlib"]System.Int32 IL_0049: call void ["mscorlib"]System.Console::WriteLine

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

) // kraj metode "CompoundAssignmentlApp::Main"!

Pogledajte istaknute linije: metoda CompoundAssignmentlApp.Get-ArrayElement se zapravo zove dvaput! Ovo je u najmanju ruku neefikasno, a možda i štetno, ovisno o tome šta još metoda radi.

Sada pogledajmo drugi kod koji koristi sintaksu složene dodjele:

korištenje sistema;

klasa CompoundAssignment2App(

zaštićeni int elementi;

public int GetArrayElementO

povratni elementi;

}

CompoundAssignment2App() (

elementi = novi int;

elemenata = 42;

}

public static void Main() (

Aplikacija CompoundAssignment2App = nova CompoundAssignment2App();

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

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

Upotreba složenog operatora dodjeljivanja rezultirat će mnogo efikasnijim MSIL kodom:

// Efikasnija tehnika: xop = y.

Metoda public hidebysig static void Main() ili upravljana

\ {

\.entrypoint

I // Veličina koda 76 (Ox4c) \ .maxstack 4

Lokalni (klasa CompoundAssignmentlApp V_0, int32 V_1) \ IL_0000: newobj instanca void CompoundAssignmentlApp::.ctor() \ IL_0005: stloc.O 1 IL_0006: Idstr "(0)" 1 IL_OOOb: ldloc.0 IL_OOOc: poziv instance 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: instanca poziva 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: dodaj

IL_002f: čelik.14

IL_0030: Idstr "(0)"

IL_0035: ldloc.0

IL_0036: poziv instance int32

CompoundAssignmentlApp::GetArrayElementO IL_003b: Idc.i4.0

IL_003c: Idelema["mscorlib"]System.Int32

IL_0041: box[mscorlib"]System.Int32

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

(klasa System.String, klasa System.Object)

IL_004b: ret ) // kraj metode "CompoundAssignmentlApp::Main"

Možete vidjeti da je korištena MSIL naredba. dup. Duplicira gornji element na steku, čineći tako kopiju vrijednosti vraćene metodom CompoundAssignmentlApp.Get element niza. I

Iz ovoga se vidi da ipak x +=y ekvivalentno x = x + y, MSIL kod je različit u oba slučaja. Ova razlika bi vas trebala natjerati da se zapitate koju sintaksu koristiti u svakom slučaju. Opće pravilo i moja preporuka je da koristite složene operatore dodjele kad god i gdje god je to moguće.

Operatori povećanja i dekrementa

Uveden u C i portiran na C++ i Java operateri inc 1 -rement i dekrement vam omogućavaju da sažeto izrazite da želite da povećate ili smanjite numeričku vrijednost za 1. To jest, /++ je ekvivalentno dodavanju 1 trenutnoj vrijednosti /".

Postojanje dva oblika operatora inkrementa i dekrementa ponekad je zbunjujuće. prefiks i postfix tipovi ovih operatora se razlikuju u trenutku u kojem se vrijednost mijenja. U verziji s prefiksom operatora inkrementa i dekrementa (++ ai - a odnosno) prvo se izvodi operacija, a zatim se kreira vrijednost. U postfix verziji (a++ i a-) prvo se kreira vrijednost, a zatim se izvodi operacija. Razmotrimo primjer:

korištenje sistema;

klasa IncDecApp(

javna statička praznina Foo(int j)

{

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

>

public static void Main() (

int i = 1;

Console.WriteLineC"flo poziva Foo(i++) = (0)", i);

Console.WriteLine("Nakon poziva Foo(i++) = (0)", i);

Console.WriteLine("\n");

\ Console.WriteLineC"flo poziva Foo(++i) = (0)", i);

\foo(++l);

\ Console.WrlteLine("Nakon poziva Foo(++i) = (0)", i);

l Rezultat izvršenja će biti sljedeći:

Prije pozivanja Foo(i++) = 1

IncDecApp.Foo j = 1

Nakon poziva Foo(i++) = 2

Prije pozivanja Foo(-n-i) = 2

IncDecApp.Foo j = 3

Nakon poziva Foo(++i) = 3

Razlika je kada vrijednost se kreira i operand se mijenja. Kada je pozvan foo(i++) vrijednost /" se prosljeđuje (nepromijenjena) metodi foo i poslije povratak iz metode / se povećava za 1. Pogledajte sljedeći MSIL kod: naredba dodati izvršava se nakon guranja vrijednosti na stek.

IL.0013: ldloc.0

IL.0014: dup

IL_0015: Idc.i4.1

IL_0016: dodaj

IL_0017: stloc.O

IL_0018: poziv void IncDecApp::Foo(int32)

Sada pogledajte oblik prefiksa operatera koji se koristi u pozivu foo(++a). U ovom slučaju, MSIL kod će biti drugačiji. Istovremeno, tim dodati izvedeno prije kako se vrijednost gura u stog za kasnije pozivanje metode foo.

IL.0049: ldloc.0

IL_004a: Idc.i4.1

IL_004b: dodaj

IL_004c: dup

IL_004d: stloc.O

IL_004e: poziv void IncDecApp::Foo(int32)

Relacioni operateri

Većina operatora vraća numeričke vrijednosti. Što se tiče relacijskih operatora, oni generiraju boolean rezultat. Umjesto / izvođenja matematičkih operacija nad skupom operanda, / relacijski operatori analiziraju odnos između operanada i povratak značenje istinito, ako je omjer tačan, lažno- ako je/ lažno.

Operatori poređenja

Za relacijske operatore pozvane operatori poređenja, refer)-sya "manje" (<), «меньше или равно» (<=), «больше» (>), veće ili jednako (>=), jednako (==), a nije jednako (!=). Primena ovih operatora na brojeve je jasna, ali kada se koriste sa objektima, njihova implementacija nije tako očigledna. Evo primjera:

korištenje sistema;

klasa NumericTest(

javni numerički test (int 1)

{

this.i = i;

>

zaštićeni int 1; )

klasa RelationalOpslApp(

public static void Main() (

NumericTest testl = novi NumericTest(42); NumericTest test2 = novi NumericTest(42);

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

Ako ste Java programer, znate šta će se ovde dogoditi. Međutim, C++ programeri će vjerovatno biti iznenađeni kada vide rezultat false. Da vas podsjetim: kreiranjem instance objekta, dobijate referencu na njega. To znači da kada naiđe na relacioni operator koji upoređuje dva objekta, C# prevodilac ne upoređuje sadržaj objekata, već njihove adrese. Da biste ovo bolje razumjeli, razmotrite MSIL kod:

\ .method public hldebysig static void MainQ ili upravljan

\ .entrypoint

\ // Veličina koda 39 (0x27)

1.maxstack 3

Lokalno stanovništvo (klasa NumericTest V_0, \ klasa NumericTest V_1, 1 bool V_2)

ILJJOO: Idc.i4.s 42

1L_0002: newobj instanca void NumericTest::.ctor(int32)

IL_0007: stloc.O

IL_0008: Idc.i4.s 42

IL_OOOa: newobj instanca void NumericTest::.ctor(int32)

IL_OOOf: stloc.1

IL_0010: Idstr "(0)"

IL_0015: ldloc.0

IL_0016: ldloc.1

IL_0017: ekv

IL_0019: stloc.2

IL_001a: Idloca.s V_2

IL_001c: box["mscorlib"]System.Boolean

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

(klasa System.String, klasa System.Object)

IL_0026: ret ) // kraj metode "RelationalOpslApp::Main"

Pogledaj liniju .locals. Kompajler specificira da je metoda Main tri lokalne varijable. Prva dva su objekti numerički test, treća je logička varijabla. Sada pređimo na linije IL_0002 i IL_0007. Ovdje se instancira objekt testl, i povežite se na njega sa stloc pohranjen u prvoj lokalnoj varijabli. Važno je da MSIL sačuva adresu novokreiranog objekta. Zatim u redovima IL_OOOa i IL_OOOf vidite MSIL kodove za kreiranje objekata test2 i pohranjivanje vraćene reference u drugu lokalnu varijablu. Konačno, u redovima 1LJ-015 i IL_0016 lokalne varijable se guraju u stog naredbom IDloc, i u redu IL_0017 tim siva uspoređuje dvije vrijednosti na vrhu steka (tj. reference objekata testl i testl). Povratna vrijednost se pohranjuje u treću lokalnu varijablu, a zatim izlazi pomoću metode System.Console. writeline.

Ali kako uporediti članove dva objekta? Odgovor je korištenje implicitne osnovne klase svih .NET Framework objekata. Naime, za ove svrhe, klasa System.Object postoji metoda Jednako. Na primjer, / sljedeći kod uspoređuje sadržaj objekata i izlaza, kao što biste očekivali, istina: ja

korištenje sistema; /

klasa RelationalOps2App

( / public static void Main() (

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

Primjer RelationalOpslApp koristi "self-made" klasu (Nu-mericTest), i u drugom primjeru - .NET klasa (Decimalno). Poenta je da metoda System.Object.Equals mora biti poništeno da bi se izvršilo stvarno poređenje članova. Dakle, metoda Jednako sa klasom NumericTest neće raditi jer nismo nadjačali metodu. A evo i časa Decimala nadjačava metodu koju nasljeđuje jednaki, i u ovom slučaju će sve funkcionirati.

Drugi način za poređenje objekata je korištenje preopterećenja operatera(preopterećenje operatera). Preopterećenje operatora definira operacije koje će se izvršiti na objektima određenog tipa. Na primjer, za objekte string Operator + ne vrši sabiranje, već spaja nizove. Preopterećenje operatera ćemo pokriti u 13. poglavlju.

Jednostavni operatori dodjele

Poziva se vrijednost na lijevoj strani iskaza o dodjeli vrijednost, a na desnoj strani - rvalue. As rvalue može biti bilo koja konstanta, varijabla, broj ili izraz čiji je rezultat kompatibilan lvalue. U međuvremenu lvalue mora biti varijabla određenog tipa. Poenta je da se vrijednost kopira s desne na lijevu stranu. Stoga se za novu vrijednost mora dodijeliti fizički adresni prostor. Na primjer, možete napisati /" = 4, jer / ima mjesto u memoriji - na steku ili na hrpi - ovisno o vrsti /. A evo i operatera 4 = 1 ne može se izvršiti jer je 4 vrijednost, a ne varijabla čiji se sadržaj u memoriji može promijeniti. Usput, napominjem da u C# as lvalue može biti varijabla, svojstvo ili indekser. Više o svojstvima i indeksatorima potražite u poglavlju 7. U ovom poglavlju koristim varijable radi jednostavnosti. Ako sa zadatkom numeričke vrijednosti sve je dovoljno jasno, sa objektima je stvar komplikovanija. Dozvolite mi da vas podsjetim da kada radite sa objektima, ne manipulišete elementima steka, koje je lako kopirati i premještati. U slučaju objekata, zaista imate reference samo na neke entitete kojima je dinamički dodijeljena memorija. Stoga, kada pokušate da dodijelite objekt (ili bilo koji referentni tip) varijabli, ne kopiraju se podaci, kao što je slučaj sa tipovima vrijednosti, već reference.

Recimo da imate dva objekta: testl i test2. Ako navedete testl= test2, testl neće biti kopija test2. Oni će se poklopiti! Objekt testl ukazuje na istu memoriju kao test2, i sve promjene na objektu testl dovesti do promjena test2. Evo programa koji to ilustruje:

korištenje sistema;

klasa Foo(

public int i; )

klasa RefTestlApp(

javna statička praznina MainO(

Foo testl = novi Foo(); testl.i = 1;

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

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

testl = test2;

Console.Writel_ine("Nakon dodjeljivanja objekata");

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

testl.i = 42; ;"

Console.WriteLine("Nakon promjene samo člana TEST1"); Console.WriteLine("test1.i=(0)", testl.i); Console.WriteLine("test2.i=(0)", test2.i); Console.WriteLine("\n"); ) )

Kada pokrenete ovaj kod, vidjet ćete:

Prije dodjele objekta

test1.i=1

test2.i=2

Nakon dodjele objekta

testt.i=2

test2.i=2

Nakon promjene samo TEST1 člana

test1.i=42

test2.i=42

Hajde da vidimo šta se dešava u svakoj fazi izvršenja ovog primera. foo- to je jednostavna k klasa sa jednim članom, /. Dvije instance ove klase kreiraju se u metodi Main: testl i test2- i njihovi članovi i su postavljene na 1 i 2 respektivno. Ove vrijednosti se zatim izlaze, i prema očekivanjima, testl.i jednako 1, a test2.i- 2. I tu počinje zabava! AT sljedeći red objekt testl dodeljeno test2.Čitaoci Java programiranja znaju šta je sledeće. Međutim, većina C++ programera će očekivati ​​člana/objekat testl je sada jednako članu objekta test2(pod pretpostavkom da će se prilikom kompajliranja takve aplikacije izvršiti neka vrsta operatora kopiranja člana objekta). Izgleda da izlazni rezultat to potvrđuje. Međutim, zapravo je veza između objekata sada mnogo dublja. Dodijelimo terminu vrijednost 42 testl.i i ponovo ispiši rezultat. I?! Prilikom promjene objekta testl promijenio i testZ Ovo se dogodilo zbog objekta testl dosta. Nakon što ga dodijeli test2 objekat testl je izgubljen jer se aplikacija više ne poziva na njega i kao rezultat je "čišćena" od strane sakupljača smeća (garbage collector, GC). Sad testl i test2 pokažite na istu memoriju na hrpi. Stoga, kada se promijeni jedna varijabla, korisnik će vidjeti promjenu u drugoj.

Obratite pažnju na posljednja dva izlazna reda: iako je samo vrijednost promijenjena u kodu testl.i, značenje test2.i takođe promenio. Još jednom, obje varijable sada ukazuju na istu memorijsku lokaciju, što je ponašanje koje bi Java programeri očekivali. Međutim, to uopće ne ispunjava očekivanja C++ programera, jer se u ovom jeziku vrši kopiranje objekata: svaka varijabla ima svoju jedinstvenu kopiju članova i promjene na jednom objektu ne utiču na drugi. Budući da je ovo ključ za razumijevanje kako objekti rade u C#, hajde da napravimo korak unazad i vidimo šta se dešava kada prosledimo objekat metodi:

korištenje sistema;

klasa Foo(

public int i; )

klasa RefTest2App(

public void ChangeValue (Foo f)

{

f.i = 42;

}

public static void Main() (

RefTest2App app = nova RefTest2App();

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

Console.WriteLine("Prije pozivanja metode"); Console.WriteLine("test.i=(0)", test.i); Console.WriteLine("\n");

app.ChangeValue(test);

Console.WriteLine("Nakon poziva metode"); Console.WriteLine("test.i=(0)", test.i); Console.WriteLine("\n"); > )

U većini jezika osim Jave, ovaj kod će kopirati kreirani objekt testirati u metoda lokalnog steka RefTest2App.ChangeValue. U ovom slučaju, objekt test, kreiran u metodi glavni, nikada neće vidjeti promjene objekta/ napravljene u metodi ChangeValue. Međutim, ponavljam da je metoda Main prosljeđuje referencu na objekt dodijeljen hrpi test. Kada je metoda ChangeValue manipulira svojom lokalnom varijablom // također direktno manipulira objektom test metoda main.

Sažimanje

Glavna stvar u svakom programskom jeziku je način na koji se izvode dodjeljivanje, matematičke, logičke i relacijske operacije - sve što je potrebno za rad. stvarne aplikacije. U kodu, ove operacije su predstavljene operatorima. Faktori koji utiču na izvršenje naredbi uključuju prioritet i asocijativnost (lijevo i desno) naredbi. C#-ov moćan skup predefiniranih operatora može se proširiti korisnički definiranim implementacijama, koje ćemo pokriti u 13. poglavlju.

Posljednje ažuriranje: 19.06.2017

Odvojeni skup operacija predstavlja uslovne izraze. Takve operacije vraćaju logičku vrijednost, odnosno vrijednost tipa bool : true ako je izraz tačan i false ako je izraz netačan. Ove operacije uključuju operacije poređenja i logičke operacije.

Operacije poređenja

Operatori poređenja upoređuju dva operanda i vraćaju bool - true ako je izraz tačan i netačan ako je izraz netačan.

    Uspoređuje dva operanda radi jednakosti. Ako su jednaki, tada operacija vraća true , ako nisu jednaki, onda se vraća false:

    B; // false

    Uspoređuje dva operanda i vraća true ako operandi nisu jednaki i false ako su jednaki.

    int a = 10; int b = 4; bool c = a != b; // istina bool d = a!=10; // false

    Manje od operacije. Vraća istinito ako je prvi operand manji od drugog i lažno ako je prvi operand veći od drugog:

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

    Operacija "veće od". Uspoređuje dva operanda i vraća true ako je prvi operand veći od drugog, u suprotnom vraća false:

    int a = 10; int b = 4; bool c = a > b; // istina bool d = a > 25; // false

    Operacija manja ili jednaka. Uspoređuje dva operanda i vraća true ako je prvi operand manji ili jednak drugom. U suprotnom vraća false.

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

    Veće ili jednako operaciji. Uspoređuje dva operanda i vraća true ako je prvi operand veći ili jednak drugom, u suprotnom vraća false:

    int a = 10; int b = 4; bool c = a >= b; // istina bool d = a >= 25; // false

Operacije<, > <=, >= imaju veći prioritet od == i !=.

Bulove operacije

C# također definira logičke operatore koji također vraćaju bool vrijednost. Oni prihvataju bool vrijednosti kao operande. Obično se primjenjuje na odnose i kombinira višestruke operacije poređenja.

    Operacija logičkog sabiranja ili logičkog ILI. Vraća true ako barem jedan od operanada vraća true.

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

    Logičko množenje ili logičko I. Vraća tačno ako su oba operanda tačna u isto vrijeme.

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

    Operacija logičkog sabiranja. Vraća true ako barem jedan od operanada vraća true.

    bool x1 = (5 > 6) || (4< 6); // 5 >6 - netačno, 4< 6 - true, поэтому возвращается true bool x2 = (5 >6) || (4 > 6); // 5 > 6 je netačno, 4 > 6 je netačno, pa se vraća false

    Operacija logičkog množenja. Vraća true ako su oba operanda istinita.

    bool x1 = (5 > 6) && (4< 6); // 5 >6 - netačno, 4< 6 - true, поэтому возвращается false bool x2 = (5 < 6) && (4 < 6); // 5 < 6 - true, 4 >6 je istina pa se vraća true

    Operacija logičke negacije. Izvodi se na jednom operandu i vraća true ako je operand netačan. Ako je operand istinit, tada operacija vraća false:

    bool a = istina; bool b = !a; // false

    Ekskluzivna operacija ILI. Vraća true ako su prvi ili drugi operand (ali ne oba) tačni, u suprotnom vraća false

    bool x5 = (5 > 6)^(4< 6); // 5 >6 - netačno, 4< 6 - true, поэтому возвращается true bool x6 = (50 > 6) ^ (4 / 2 < 3); // 50 >6 - istina, 4/2< 3 - true, поэтому возвращается false

Ovdje imamo dva para operacija | i || (kao i & i &&) izvode slične radnje, ali one nisu ekvivalentne.

U izrazu z=x|y; i x i y vrijednosti će biti izračunate.

U izrazu z=x||y; prvo će se izračunati vrijednost x, a ako je jednaka true , tada izračunavanje vrijednosti y više nema smisla, jer u svakom slučaju već imamo z jednako true . Vrijednost y će biti procijenjena samo ako je x netačno

Isto važi i za &/&& par operacija. U izrazu z=x izračunat će se obje vrijednosti - x i y.

U izrazu z=x&, prvo će se izračunati x vrijednost, a ako je jednaka false, tada izračunavanje vrijednosti y više nema smisla, jer u svakom slučaju već imamo z jednako false. Vrijednost y će biti procijenjena samo ako je x istinito

Dakle, operacije || i && su pogodniji u proračunima, jer omogućavaju smanjenje vremena za procjenu vrijednosti izraza i time poboljšavaju performanse. I operacije | i & su pogodniji za izvođenje bitnih operacija nad brojevima.

Operator && ima prednost nad operatorom ||. Dakle, u izrazu istina || true && false podizraz true && false se prvo izvršava.

Top Related Articles