670 likes | 814 Views
RP3/predavanje02. Programski jezik C#: Tipovi. Primjer C# programa. using System; class Test { static void Main( ) { int x=26; Console.WriteLine(x); } }. Uključivanje imeničkog prostora. Using se koristi samo za prostore, ne i za tipove.
E N D
RP3/predavanje02 Programski jezik C#: • Tipovi ---------- Računarskipraktikum 3 ---------- Maja Starčević
Primjer C# programa using System; class Test { static void Main( ) { int x=26; Console.WriteLine(x); } } Uključivanje imeničkog prostora. Using se koristi samo za prostore, ne i za tipove. Dakle, greška je pisati: using System.Console; Definicija klase Definicija metode Console=System.Console -------Računarski praktikum 3-------
Primjer C# programa Konzolna aplikacija u Visual Studiu: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[ ] args) { …….. } } } -------Računarski praktikum 3-------
Ključne riječi -------Računarski praktikum 3-------
Ključne riječi -------Računarski praktikum 3-------
Ključne riječi -------Računarski praktikum 3-------
Ključne riječi Napomena: ključna riječ se može koristiti kao identifikator s @ prefiksom, npr: class @class { … } . Neke ključne riječi su kontekstualne (u zelenim poljima). Kontekstualne riječi imaju posebno značenje u određenim dijelovima programa dok se u ostalim dijelovima mogu koristiti kao identifikatori. Ostale riječi se ne mogu koristiti kao identifikatori ni u jednom dijelu programa. -------Računarski praktikum 3-------
Identifikatori Kod identifikatora (imena varijabli, funkcija, klasa…) razlikujemo velika i mala slova. Uobičajeno je argumente, lokalne varijable i privatne varijable članice klasa pisati camel notacijom (npr. prvaKlasa, brojUcitanihPodataka …). Ostale identifikatore pišemo koristeći Pascal notaciju (npr. MojaPrvaMetoda). -------Računarski praktikum 3-------
Kontrola toka Kontrola toka se vrši jednako kao i u C++-u pomoću ključnih riječi for, while, do, if, switch, case. Nove ključne riječi u tom kontekstu u C#-u su foreach i in koje se koriste za iteriranje kroz kolekcije (spremnike). Kod switch bloka postoje male razlike u odnosu na C++ kao što se vidi iz sljedećeg primjera. -------Računarski praktikum 3-------
Switch string[] dani = { "Pon", "Uto", "Sri", "Cet", "Pet", "Sub" }; foreach (string dan in dani) { switch (dan) { case "Pon": Console.WriteLine("Radno vrijeme : 8-17"); break; case "Uto": case "Sri": Console.WriteLine("Radno vrijeme : 8-20"); break; case "Cet": goto case "Pon"; case "Pet": Console.WriteLine("Radno vrijeme : 8-15"); break; default: Console.WriteLine("Niste odabrali radni dan"); break; } } Ako izbacimo break, kompilator javlja grešku. -------Računarski praktikum 3-------
Tipovi -------Računarski praktikum 3-------
Tipovi Napomena: svi vrijednosni tipovi (osim enumeracija) su u biti strukture. Vrijednosni tipovi su izvedeni iz System.ValueType klase koja direktno nasljeđuje klasu System.Object. Bazna klasa za enumeracije je System.Enum koja isto nasljeđuje System.ValueType. Klase ValueType i Enum su apstraktne klase. -------Računarski praktikum 3-------
.NET tipovi -------Računarski praktikum 3-------
.NET tipovi -------Računarski praktikum 3-------
Vrijednosni tipovi Varijable ili konstante vrijednosnog tipa su naprosto vrijednosti. Definicija strukture SPoint: Instanca strukture SPoint u memoriji: public struct SPoint { public int X; public int Y; } X Y Članovi strukture su implicitno private ! -------Računarski praktikum 3-------
Vrijednosni tipovi Operator new nije nužan. Možemo zamijeniti s: Point p1; Međutim, u tom slučaju varijable strukture nisu inicijalizirane. Moramo ih inicijalizirati prije pristupa. SPoint p1=new SPoint (); p1.X=2; SPoint p2=p1; Console.WriteLine(p1.X); // 2 Console.WriteLine(p2.X); // 2 p1.X=5; Console.WriteLine(p1.X); // 5 Console.WriteLine(p2.X); // 2 Pridruživanjem instance vrijednosnog tipa zapravo se vrši kopiranje vrijednosti instance. Ne utječe na p2. -------Računarski praktikum 3-------
Vrijednosni tipovi U memoriji imamo na kraju sljedeće: p1 p2 5 0 2 0 -------Računarski praktikum 3-------
Ugrađeni tipovi U C#-u tip int je isto što i System.Int32 koji je primjer strukture. Na varijablama ugrađenih tipova možemo zvati i metode. U sljedećem primjeru dohvatit ćemo dvije konstante iz strukture System.Int32 (pritom moramo koristiti ime tipa, System.Int 32 ili int) te ćemo pozvati jednu metodu. int i = int.MaxValue; int j = int.MinValue; Console.WriteLine(i.CompareTo(j)); -------Računarski praktikum 3-------
Referentni tipovi Referentni tip je nešto složeniji od vrijednosnog tipa jer se uz objekt kreira i referenca na taj objekt. Varijabla ili konstanta referentnog tipa je zapravo referenca na objekt koji sadrži vrijednosti. public class CPoint { public int X; public int Y; } Metapodaci objekta X Y referenca -------Računarski praktikum 3-------
Referentni tipovi CPoint p1=new CPoint (); p1.X=2; CPoint p2=p1; Console.WriteLine(p1.X); // 2 Console.WriteLine(p2.X); // 2 p1.X=5; Console.WriteLine(p1.X); // 5 Console.WriteLine(p2.X); //5 Kopiranje reference (p1 i p2 su reference na isti objekt) -------Računarski praktikum 3-------
Referentni tipovi Prikaz u memoriji: Referenca p1 Metapodaci objekta 5 0 Referenca p2 -------Računarski praktikum 3-------
Null Referenci se može dodijeliti literalnull. U tom slučaju referenca ne pokazuje ni na jedan objekt. Point p=null; Console.WriteLine (p.X) //error Vrijednosnim tipovima se ne može dodijeliti vrijednost null. Napomena: vidi “nullable” tipove. -------Računarski praktikum 3-------
Pokazivači C# pruža podršku i za direktno upravljanje memorijom pomoću pokazivača međutim blokovi koda u kojima se koriste pokazivači moraju biti označeni ključnom riječi unsafe (i kompilirani s /unsafe opcijom). Pokazivački tipovi se u pravilu koriste za inteoperabilnost s C-ovskim APIjima i hvatanje memorije izvan upravljane hrpe. unsafe { // kod s pokazivačima } -------Računarski praktikum 3-------
Memorijski blokovi Stog (stack) je memorijski blok za pohranu varijabli (objekata kod vrijednosnih tipova, referenci za referentne objekte). Radi standardno na principu last-in first-out. “Hrpa” (heap) je memorijski blok u koji se smještaju referentni objekti. Referenca na objekt smješta se na stog. “Sakupljač otpada” (Garbage Collector - GC) periodički uklanja objekte s heap-a. Da bi se to dogodilo, objekt ne smije imati referencu na sebe. -------Računarski praktikum 3-------
Memorijski blokovi Na heap se također smještaju i statičke varijable članice, kao i konstante (za njih nije zadužen GC). Primjer: Ako unutar neke funkcije kreiramo lokalni objekt referentnog tipa, objekt se smješta na heap, a referenca na njega na stog. Pri izlasku iz funkcije referenca se briše sa stoga, objekt više nema referencu na sebe i GC ga može pokupiti. Važno: ne možemo eksplicitno izbrisati objekte (kao u C++-u). -------Računarski praktikum 3-------
Lokalne varijable Nije dozvoljeno deklarirati varijablu istog imena u istom ili ugniježdenom bloku: static void Main(string[] args) { int a; { int b; } { int a; // greška int b; // u redu } for (int i = 0; i < 5; ++i) Console.Write(i); int i = 15; // greška } -------Računarski praktikum 3-------
Inicijalizacija Izvan unsafe konteksta nemoguće je pristupiti neinicijaliziranoj memoriji. Konkretno: • Lokalnim varijablama se mora dodijeliti vrijednost prije čitanja. • Argumentima funkcije se mora dodijeliti vrijednost prije poziva funkcije. • Automatski se inicijaliziraju elementi polja (polje je zapravo samo specijalan primjer klase). -------Računarski praktikum 3-------
Inicijalizacija class Program { static void Main(string[] args) { string s; int i; int[] matrica = new int[4]; Klasa k = new Klasa(); Console.WriteLine("{0}, {1}, {2}, {3}", i, s, k.i, k.s); foreach (int j in matrica) Console.WriteLine(j); } } Zadatak: Što će ispisati sljedeći kod? class Klasa { public int i; public string s; } -------Računarski praktikum 3-------
Inicijalizacija class Program { static void Main(string[] args) { string s=“neki tekst”; int i=13; int[] matrica = new int[4]; Klasa k = new Klasa(); Console.WriteLine("{0}, {1}, {2}, {3}", i, s, k.i, k.s); foreach (int j in matrica) Console.WriteLine(j); } } Odgovor: Kompilator javlja grešku (lokalnim varijablama nije dodijeljena vrijednost prije čitanja). Popravimo -------Računarski praktikum 3-------
Inicijalizacija Nakon ispravljanja koda, izlaz je sljedeći: 13, neki tekst, 0, 0 0 0 0 k.s=null Primijetimo da su elementi polja matrica automatski inicijalizirani na 0. Automatski su inicijalizirani i članovi objekta k. -------Računarski praktikum 3-------
Inicijalizacija Vrijednosti za p.X i p.Y su dodijeljene preko (implicitno definiranog) konstruktora strukture. Lokalnoj varijabli t nisu dodijeljene vrijednosti prije čitanja. class Program { staticvoidMain(string[] args) { SPoint p=new SPoint(); SPoint t; Console.WriteLine("{0}, {1}", p.X, p.Y); Console.WriteLine("{0}, {1}", t.X, t.Y); } } error struct SPoint { public int X; public int Y; } -------Računarski praktikum 3-------
Inicijalizacija class Program { static void Main(string[] args) { SPoint p=new SPoint(); SPoint t; t.X=1; t.Y=2; Console.WriteLine("{0}, {1}", p.X, p.Y); Console.WriteLine("{0}, {1}", t.X, t.Y); } } Kompilator javlja grešku za prethodni kod. Moramo dodijeliti vrijednosti za t.X i t.Y. struct SPoint { public int X; public int Y; } Output: 0, 0 1, 2 -------Računarski praktikum 3-------
Tip object System.Object je najviše rangirana temeljna klasa za sve tipove. Sadrži sljedeće članove: public class Object { public Object( ); public extern Type GetType ( ); public virtual bool Equals (object obj); public static bool Equals (object objA, object objB); public static bool ReferenceEquals (object objA, object objB); public virtual int GetHashCode( ); public virtual string ToString( ); protected override void Finalize( ); protected extern object MemberwiseClone( ); } -------Računarski praktikum 3-------
Pakiranje Pakiranje (engl. boxing) nam omogućava da vrijednosni tip pretvorimo u referentni. Konkretno, vrijednost pakiramo u instancu klase object (koja je naravno referentni tip). int i = 10; object o = (object)i; //pakiramo int u object eksplicitno // object o=i; // možemo to napraviti i implicitno int k = (int)o; //raspakiramo object i dobivamo int Možemo raspakirati (engl. unboxing) samo referencu na objekt koji je nastao pakiranjem i pritom tip u koji ćemo raspakirati mora odgovarati tipu koji je bio pakiran (inače se baca InvalidCastException). Pakiranje se smatra skupom operacijom. -------Računarski praktikum 3-------
Vrijednosni tipovi Zadatak: pronađite greške u kodu. staticvoidMain(string[] args) { SPoint p = new SPoint(); p = null; object o = p; o = null; SPoint r; object oo = r; } -------Računarski praktikum 3-------
Vrijednosni tipovi staticvoidMain(string[] args) { SPoint p = new SPoint(); //objekt se kreira pomoću default konstruktora (inicijaliziran je) p = null; // varijabli vrijednosnog tipa se ne može pridružiti null object o = p; // pakiranje tipa u referentni (boxing) o = null; // sad je u redu SPoint r; // ova varijabla je samo deklarirana, a ne i inicijalizirana object oo = r; // pridruživanje neinicijalizirane varijable je greška } -------Računarski praktikum 3-------
Vrijednosni tipovi Zadatak: koje će se metode pozvati u sljedećem primjeru? struct S { int x, y; public override string ToString() { return "U strukturi su " + x + " i " + y; } } -------Računarski praktikum 3-------
Vrijednosni tipovi class Program { static void f(object o) { Console.WriteLine("f(object) " + o); } static void f(string s) { Console.WriteLine("f(string) " + s); } static void Main(string[] args) { S str = new S(); f(str); // pakiranje f(str.ToString()); } } -------Računarski praktikum 3-------
Vrijednosni tipovi -------Računarski praktikum 3-------
Inicijalizacija Konstruktor ne sadrži inicijalizacijsku listu (kao u C++-u), već se inicijalizacija događa ili implicitno ili direktno pri deklaraciji. class PrvaKlasa { public int i; //implicitna inicijalizacija } class DrugaKlasa { public int p=2; public PrvaKlasa pk=new PrvaKlasa(); /* eksplicitna inicijalizacija pri deklaraciji */ } class Program { static void Main(string[] args) { DrugaKlasa dk=new DrugaKlasa(); Console.WriteLine("{0},{1}", dk.p, dk.pk.i); } } Output: 2, 0 -------Računarski praktikum 3-------
Literali Integralni literali koriste decimalnu ili heksadecimalnu notaciju, dok realni koriste decimalnu ili eksponencijalnu notaciju. int x=100, y=0x2B; double a=2.45, b=2E05; Ukoliko literal sadrži decimalnu točku ili E, tretira se kao double. Inače mu se dodjeljuje prvi odgovarajući tip iz liste int, uint, long, ulong. -------Računarski praktikum 3-------
Literali Pomoću numeričkih sufiksa eksplicitno definiramo tip literala. Najčešće se koriste sufiksi za specificiranje float i decimal literala jer se bez sufiksa literal tretira kao double. To predstavlja problem jer ne postoji implicitna konverzija iz tipa double u tipove decimal i float. float f=3.45; // greška float f=3.45F; //ispravno -------Računarski praktikum 3-------
Konverzije Float tip se implicitno konvertira u double. Obrnuta konverzija mora biti eksplicitna. Svi integralni tipovi se implicitno konvertiraju u realne. Obrat zahtjeva eksplicitnu konverziju. Napomena: byte, sbyte, short i ushort ne definiraju aritmetičke operatore. Kod tih operacija stoga dolazi do implicitne konverzije u širi tip (int). -------Računarski praktikum 3-------
Konverzije Zadatak: što ispisuje sljedeći kod? int a = 0; if (a = 1) { } Console.Write(a); -------Računarski praktikum 3-------
Konverzije Rješenje: kod se ne može kompilirati jer nije definirana implicitna konverzija iz int u bool. Napomena: C++ ispisuje 1. U C#-u if radi samo s bool varijablom: int a = 0; if (a == 1) { } Console.Write(a); // 0 -------Računarski praktikum 3-------
var Ukoliko se varijabla deklarira i inicijalizira u jednom retku, kompilator je ponekad u stanju sam odrediti njezin tip. U tom slučaju nije potrebno navoditi tip varijable, već se on može zamijeniti s ključnom riječi var. var p=4; // ekvivalentno s // int p=4; -------Računarski praktikum 3-------
Specijalne float i double vrijednosti Console.WriteLine (1.0/0.0); // Infinity Console.WriteLine (1/0); // error Console.WriteLine (0.0/0.0); // NaN Console.WriteLine(0.0/0.0 ==double. NaN); // False Console.WriteLine(double.isNan(0.0/0.0)); // True -------Računarski praktikum 3-------
checked operator Ovaj operator provjerava izraze s +, -, *, /, ++, --, unarnim –. int a=1000000, b=1000000; int c; ili checked { c=a*b; } int c=checked (a*b); // Unhandled Exception: System.OverflowException: Arithmetic Operation resulted in an overflow -------Računarski praktikum 3-------
checked operator Primjer 1: static void Main(string[] args) { int x = 1000000, y = 1000000; int z = x * y; Console.Write(z); // -727379968 unchecked { int xx = 1000000, yy = 1000000; int zz = xx * yy; Console.Write(zz); // -727379968 } -------Računarski praktikum 3-------
checked operator try { checked { int a = 1000000, b = 1000000; int c = a * b; Console.Write(c); } } catch (OverflowException e) { Console.WriteLine("Uhvatio overflow"); } catch (Exception e) {Console.WriteLine(e.ToString()); } } -------Računarski praktikum 3-------