530 likes | 679 Views
RP3/predavanje06. Generici Kolekcije String, StringBuilder. Generički tipovi i metode. Višestruka iskoristivost koda može se postići nasljeđivanjem baznog tipa ili pomoću generika. Generici povećavaju tipsku sigurnost i smanjuju potrebu za kastanjem i pakiranjem.
E N D
RP3/predavanje06 • Generici • Kolekcije • String, StringBuilder ---------- Računarski praktikum 3 ---------- Maja Starčević
Generički tipovi i metode Višestruka iskoristivost koda može se postići nasljeđivanjem baznog tipa ili pomoću generika. Generici povećavaju tipsku sigurnost i smanjuju potrebu za kastanjem i pakiranjem. Generički tip sadrži generički parametar koji korisnik zamjenjuje s konkretnim tipom. Primjer: otvoreni tip List<T> --- > zatvoreni tip List<string> Računarski praktikum 3
Generički tipovi Generički parametri mogu se nalaziti u deklaraciji klase, strukture, metoda, sučelja i delegata. U deklaraciji se može nalaziti i više takvih parametara: class Dictionary<TKeyValue, TValueType> { … } Dozvoljeno je preopterećivanje generičkih tipova i metoda, odnosno definiranje više tipova ili metoda s istim imenom, ali različitim brojem generičkih parametara. Računarski praktikum 3
Generičke metode Generičke metode sadrže generičke parametre unutar potpisa. static void Zamijeni<T> (ref T a, ref T b) { T temp=a; a=b; b=temp; } ---------------------------------------------------------- int x=1, y=3; Zamijeni(ref x, ref y); // Kompilator implicitno dodjeljuje tip int Zamijeni<int>(ref x, ref y) ; // Može i eksplicitno Računarski praktikum 3
Generički tipovi Na generičke parametre se mogu primijeniti ograničenjaako se zahtijeva veća specifikacija tipa. Računarski praktikum 3
Generički tipovi Ukoliko se u listi nalazi više generičkih parametara s ograničenjem, navodimo where za svaki posebno: class Klasa< T , U > where T: struct where U: class, new( ) { …… } Primjer generičkog delegata: delegate T MyDelegate<T>( ) where T : new ( ) Računarski praktikum 3
Generički tipovi class Klasa { int a; } class C<T> where T:struct { T t; } class D<T> where T :class { T t; } class Program { static void Main(string[] args) { C<int> c1; // C<Klasa> c2; // D<int> d1; D<Klasa> d2; } } Računarski praktikum 3
Generički tipovi Zadatak: koje su od sljedećih generičkih metoda dobro definirane? public static bool Usporedi1<T>(T a, T b) { return a == b; } public static bool Usporedi2<T>(T a, T b) where T : struct { return a == b; } public static bool Usporedi3<T>(T a, T b) where T : class { return a == b; } public static bool Usporedi4<T>(T a, T b) { return a.Equals(b); } public static bool Usporedi5<T>(T a, T b) { return ReferenceEquals(a, b); } Računarski praktikum 3
Generički tipovi Odgovor: Metode Usporedi1 i Usporedi 2 ne rade na svim vrijednosnim tipovima (nije osigurano da je operator == definiran za sve moguće strukture). public static bool Usporedi1<T>(T a, T b) { return a == b; } // greška public static bool Usporedi2<T>(T a, T b) where T : struct { return a == b; } // greška public static bool Usporedi3<T>(T a, T b) where T : class { return a == b; } public static bool Usporedi4<T>(T a, T b) { return a.Equals(b); } public static bool Usporedi5<T>(T a, T b) { return ReferenceEquals(a, b); } Računarski praktikum 3
Generički tipovi Zadatak: popravite kod interface ICitljivo { void Citaj( );} class C<T> where T: ICitljivo { T t; void f( ) { t.Citaj( ); t.Pisi( ); } } class S { void Citaj( ) { } } class Program { static void Main(string[] args) { C<S> s; } } Računarski praktikum 3
Generički tipovi interface ICitljivo { void Citaj( );} class C<T> where T: Icitljivo { T t; void f( ) { t.Citaj( ); t.Pisi( );} // T ne implementira sučelje koje pruža metodu Pisi( ) } class S : ICitljivo { public void Citaj( ) { } } class Program { static void Main(string[] args) { C<S> s; } } Računarski praktikum 3
Generički tipovi class Program { static T Zbroj<T>(T a, T b) { return a + b; //error } static void Main(string[] args) { int a=1, b=2; int c = Zbroj(a, b); } } Napomena: u prethodnoj generičkoj metodi nije osigurano da će operator zbrajanja biti definiran za svaki mogući tip T. Također, nemoguće je pozvati se direktno na sučelje s obzirom da su operatori statičke funkcije, a takve se ne mogu nalaziti u sučeljima. Računarski praktikum 3
Generički tipovi interface ICalculator<T> { T Suma(T a, T b); } struct IntCalculator : ICalculator<int> { public int Suma(int a, int b) { return a + b; } } class Program { public static T Zbroj<T, C>(T a, T b) where C : ICalculator<T>, new() { C c=new C(); return c.Suma(a, b); } static void Main(string[] args) { Console.WriteLine( Zbroj<int, IntCalculator>(1, 2) ); } } Moguće rješenje: Računarski praktikum 3
Generički tipovi Napomena: od verzije C# 4.0 moguće je koristiti i ključnu riječ dynamic: class Program { static T Zbroj<T>(T x, T y) {dynamic dx = x, dy = y;return dx + dy;} static void Main(string[] args) { int a=1, b=2; int c = Zbroj(a, b); } } Računarski praktikum 3
Generički tipovi U generičku metodu ubacit ćemo parametar tipa delegata kako bismo mogli pozivati konstruktor koji prima int: public class B { private int b; public B(){ b=0; } public B(int i){ b=i; } public override string ToString() { return b.ToString(); } } public class Program { public static T f<T>(int i, Func<int, T> metoda) where T : new() { return metoda(i); } static void Main(string[] args) { Func<int, B> del=(i=> new B(i)); B obj1=del(2); Console.WriteLine(obj1.ToString()); B obj2 = f<B>(2, del); Console.WriteLine(obj2.ToString()); } } Računarski praktikum 3
Kolekcijske klase .NET Framework sadrži kolekcijske klase Array, List, Dictionary, Queue, Stack, SortedList, SortedDictionary … (u prostorima System.Collections, System.Collections.Generic, System.Collections.Specialized …) Sadrži i dva skupa standardnih sučelja za enumeriranje i uspoređivanje objekata u kolekciji - za tipski neosigurane kolekcije i noviju verziju, za generičke, tipski osigurane kolekcije. Računarski praktikum 3
Kolekcijska sučelja Računarski praktikum 3
Array Arrayje najjednostavnija kolekcija. To je kolekcija za koju C# ima ugrađenu podršku (ugrađeni indekseri za pristupanje n-tom članu). Primjer: int[ ] matrica=new int[4] u IL-kodu kreira instancu za System.Int32[ ] (izveden iz apstraktne klase System.Array). Računarski praktikum 3
Array Metode i svojstva u System.Array: AsReadOnly( ), BinarySearch( ), Clear( ), Clone( ), ConstrainedCopy( ), ConvertAll( ), Copy( ), CopyTo( ), CreateInstance( ), Exists( ), Find( ), FindAll( ), FindIndex( ), FindLast( ), FindLastIndex( ), ForEach( ), GetEnumerator( ), GetLength( ), GetLongLength( ), GetLowerBound( ), GetUpperBound( ), GetValue( ), IndexOf( ), Initialize( ), IsFixedSize( ), IsReadOnly( ), IsSynchronized( ), LastIndexOf( ), Length( ), LongLength( ), Rank, Resize( ), Reverse( ), SetValue( ), Sort( ), SyncRoot( ), TrueForAll( ) Računarski praktikum 3
Array class Program { public static void PrintArray(object[] array) { foreach (object obj in array) Console.WriteLine(obj); } static void Main(string[ ] args) { string[ ] recenica={ "Ovo", "je" ,"primjer"}; Array.Reverse(recenica); PrintArray(recenica); Array.Sort(recenica); PrintArray(recenica); } } Output: primjer je Ovo je Ovo primjer Računarski praktikum 3
List Klasa Listpredstavlja matricu čija se veličina može po potrebi dinamički povećavati. Metode i svojstva u klasi List: Capacity, Count, Item( ), Add ( ), AddRange ( ), AsReadOnly ( ), BinarySearch( ), Clear( ), Contains( ), ConvertAll( ), CopyTo( ), Exists( ), Find( ), FindAll( ), FindIndex( ), FindLast( ), FindLastIndex( ), ForEach( ), GetEnumerator( ), GetRange( ), IndexOf ( ), Insert( ), InsertRange( ), LastIndexOf( ), Remove( ), RemoveAll( ), RemoveAt( ), RemoveRange( ), Reverse( ), Sort( ), ToArray( ), TrimExcess( ), TrimToSize( ) Računarski praktikum 3
List using System; using System.Collections.Generic; using System.Text; public class Proizvod { string naziv; decimal cijena; public Proizvod(string naziv, decimal cijena) { this.naziv = naziv; this.cijena = cijena; } public string Naziv { get { return naziv; } set { naziv = value; } } public decimal Cijena { get { return cijena; } set { cijena = value; } } } class Program { static void Main(string[] args) { List<Proizvod> lista = new List<Proizvod>(); lista.Add(new Proizvod("Coca Cola“, 5.50M)); lista.Add(new Proizvod("Sprite", 5.25M)); Console.WriteLine(lista.Capacity); // 4 lista.Capacity = 2; Console.WriteLine(lista.Capacity); // 2 Console.WriteLine(lista[1].Cijena); //5,25 } } Računarski praktikum 3
System.Collections System.Collections prostor sadrži negeneričke kolekcije poput ArrayList. Vrijednosni tipovi zahtjevaju pakiranje. using System.Collections; using System.Collections.Generic; …………. ArrayList alista = new ArrayList(); alista.Add("knjiga"); alista.Add(1); alista[1] = null; List<int> lista=new List<int>(); lista.Add(1); lista.Add(2); lista[1]=null; //greška Računarski praktikum 3
Queue Queue(red) je kolekcija koja radi na principu first-in, first-out. Svojstva i metode kolekcije Queue: Računarski praktikum 3
Queue Računarski praktikum 3
Queue class Program { static void Main(string[] args) { Queue<Proizvod> red = new Queue<Proizvod>(); Proizvod p1 = new Proizvod(“Coca Cola", 5.45M); Console.WriteLine(red.Count); Console.WriteLine(red.Contains(p1)); red.Enqueue(p1); Console.WriteLine(red.Contains(p1)); Proizvod p2 = red.Peek(); Console.WriteLine(red.Count); Console.WriteLine(p1==p2); red.Dequeue(); Console.WriteLine(red.Contains(p1)); } } Output: 0 False True 1 True False Računarski praktikum 3
Stack Stack(stog) je last-in, first-out kolekcija objekata. Metode i svojstva u kolekciji Stack: Računarski praktikum 3
Stack Računarski praktikum 3
Stack using System; using System.Collections.Generic; using System.Text; class Program { static void Main(string[] args) { Stack<int> stog = new Stack<int>(); for (int i = 0; i < 5; i++) stog.Push(i); stog.Pop(); int count = stog.Count; for(int i=0; i<count;i++) Console.WriteLine(stog.Pop()); Console.WriteLine( stog.Count); } } Output: 3 2 1 0 0 Računarski praktikum 3
Dictionary Dictionary je kolekcija koja svakoj vrijednosti pridružuje ključ. Implementira IDictionary<K,V> sučelje (K-tip ključa, V-tip vrijednosti). .NET Framework može pridružiti ključ bilo kojeg tipa (string, integer, object, ...) vrijednosti bilo kojeg tipa. U pravilu je ključ jednostavnijeg tipa. Primjer 1: u rječniku stranih riječi svakoj riječi (ključ) pridružuje se definicija (vrijednost). Primjer 2: auto-oznake i gradovi. Računarski praktikum 3
Dictionary using System; using System.Collections.Generic; using System.Text; class Program { static void Main(string[] args) { Dictionary<string, string> gradovi = new Dictionary<string, string>(); gradovi.Add("ZG", "Zagreb"); gradovi.Add("ST", "Split"); gradovi.Add("KA", "Karlovac"); gradovi.Add("RI", "Rijeka"); gradovi.Add("OS", "Osijek"); Console.WriteLine("Grad s autooznakom ST je {0}", gradovi["ST"]); } } C# implementacija svojstva Item( ) Računarski praktikum 3
Dictionary Računarski praktikum 3
Dictionary Računarski praktikum 3
Dictionary Dictionary<string, string>.KeyCollection autoOznake = gradovi.Keys; foreach (string c in autoOznake) Console.WriteLine(c); Dictionary<string, string>.ValueCollection imenaGradova = gradovi.Values; foreach (string c in imenaGradova) Console.WriteLine(c); -------------------------------------------------------------------------------------------------------------- ZG ST KA RI OS Zagreb Split Karlovac Rijeka Osijek Računarski praktikum 3
Sortirane kolekcije SortedDictionary<TKey,TValue> - kolekcija na principu ključ/vrijednost sortirana po ključu. SortedDictionary<int, string> sd = new SortedDictionary<int, string>(); sd.Add(2, "Zagreb"); sd.Add(1, "Split"); sd.Add(4, "Osijek"); sd.Add(3, "Rijeka"); foreach (KeyValuePair<int, string> kvp in sd) Console.WriteLine("{0} - {1}", kvp.Key, kvp.Value); 1 – Split 2 – Zagreb 3 – Rijeka 4 - Osijek Da smo koristli Dictionary<int, string>, ispis bi odgovarao redoslijedu ubacivanja parova. Računarski praktikum 3
IComparable Ako objekti u listi implementiraju sučelje IComparable<T>, na listu se može primijeniti Sort( ) metoda. Da bi objekt T implementirao sučelje IComparable<T> mora pružiti implementaciju CompareTo( ) metode. U sljedećem primjeru koristi se default CompareTo( ) metoda za tip string koja vraća vrijednosti -1 ( < ) , 1 ( > ) ili 0 (==). Računarski praktikum 3
IComparable class Student:IComparable<Student> { public string ime; public string prezime; public Student (string ime, string prezime) { this.ime = ime; this.prezime=prezime; } public intCompareTo(Student s) { return this.prezime.CompareTo(s.prezime); } } class Program { static void Main(string[] args) { List<Student> lista= new List<Student>(); Student s1=new Student("Marko", "Maric"); lista.Add(s1); Student s2 = new Student("Ivan", "Ivic"); lista.Add(s2); Student s3 = new Student("Ana", "Anic"); lista.Add(s3); lista.Sort(); foreach (Student s in lista) Console.WriteLine(s.ime+” “+s.prezime); } } Računarski praktikum 3
Enumerator Enumerator je klasa koja implementira sučelje IEnumerator ili generičko sučelje IEnumerator<T>. Mora implementirati metodu MoveNext (koja služi za iteriranje kroz niz) i svojstvo Current s get pristupnikom (za pristupanje trenutnom elementu niza). Enumerator je dakle read-only, forward-only kursor kroz niz vrijednosti. Računarski praktikum 3
IEnumerable Klase koje implementiraju sučelje IEnumerable ili IEnumerable<T> pružaju mogućnost korištenja foreach naredbe za iteriranje kroz niz vrijednosti pripadnog objekta. Klasa koja implementira neko od navedenih sučelja mora implementirati metodu GetEnumerator koja stvara enumerator. Napomena: sučelja IEnumerable i IEnumerator su definirana u prostoru System.Collections dok se IEnumerable<T> i IEnumerator<T> nalaze u System.Collections.Generic. Računarski praktikum 3
IEnumerable class Brojevi : IEnumerable { private List<int> lista; public IEnumeratorGetEnumerator() { foreach (int i in lista) yield return i; } public List<int> Lista { set { lista = value; } get { return lista; } } } class Program { static void Main(string[] args) { List<int> l = new List<int>(); l.AddRange(new int[] { 1, 2, 3, 4 }); Brojevi brojevi = new Brojevi(); brojevi.Lista=l; foreach (var i in brojevi) Console.Write(i); } } Računarski praktikum 3
IEnumerable class Program { static IEnumerable<int> ProstiBrojevi(int n) { for(int i=2; i<=n; ++i) { bool prost=true; for (int j=2; j<=Math.Sqrt(i); ++j) if ((i%j)==0) prost=false; if (prost) yield return i; } } staticvoidMain(string[] args) { foreach (int i inProstiBrojevi(100)) Console.Write("{0} ", i); // isti ispis se postiže i s : IEnumerator<int>enumerator = ProstiBrojevi(100).GetEnumerator(); while (enumerator.MoveNext()) Console.Write("{0} ", enumerator.Current); } } Računarski praktikum 3
IEnumerable Sada želimo da klasa umjesto sučelja IEnumerable implementira generičko sučelje IEnumerable<T>. Sučelje IEnumerable<T> proširuje sučelje IEnumerable te stoga takva klasa mora implementirati metode: IEnumerator GetEnumerator(); iz IEnumerator sučelja i IEnumerator<T> GetEnumerator() koja je dodana u IEnumerator<T> sučelje. Moramo implementirati svaku posebno jer imaju različite povratne tipove. Zbog istog potpisa jednu moramo implementirati eksplicitno. Računarski praktikum 3
IEnumerable class C : IEnumerable<int> { int[] niz = new int[10]; public IEnumerator<int> GetEnumerator() // implicitna implementacija { foreach (int i in niz) yield return i; } IEnumerator IEnumerable.GetEnumerator() // eksplicitna implementacija { return GetEnumerator(); } } Računarski praktikum 3
Zadatak Napišite klasu koja implementira IEnumerable<int> sučelje. Klasa sadrži listu brojeva. Treba implementirati i metodu Add( int ) za dodavanje broja u listu, metodu Remove( int ) kojom se izbacuje posljednji element liste koji ima zadanu vrijednost i Clear() kojom se brišu svi elementi liste. Klasa mora sadržavati i svojstvo Pomak. Ukoliko iteriramo kroz objekt klase foreach naredbom, moramo dobiti popis svih brojeva iz liste, ali ne uobičajenim redoslijedom nego sa zadanim pomakom, npr. za Pomak=3 i niz 1, 2, 3, 4, 5, 6, 7 dobivamo ispis 1, 4, 7, 3, 6, 2, 5. Ukoliko ne možemo na taj način proći kroz cijeli niz, mora se izbaciti iznimka s odgovarajućom porukom. U klasu stavite i funkciju Test( int ) koja testira foreach na nizu prvih n brojeva. Računarski praktikum 3
String Puna deklaracija klase System.String (alias string u C#-u) glasi: public sealed class String : IComparable, IComparable<String>, ICloneable, IConvertible, IEnumerable, IEnumerable<char>, IEquatable<String> Računarski praktikum 3
String class Program { staticvoid Usporedi(string a, string b) { Console.WriteLine("{0}, {1}, {2}", a == b, Object.ReferenceEquals(a, b), a.Equals(b)); } staticvoidMain(string[] args) { string s1 = "Rp3"; string s2 = "Rp3"; Usporedi(s1, s2); string s3= "Racunarski"; string s4 = s3; s3 += "praktikum 3"; // string je nepromjenjiv tip, konkatenacijom se zapravo stvara novi Usporedi(s3, s4); // string, referenca s3 se prebacuje na novi string } } Računarski praktikum 3
String class Program { staticvoid Usporedi(string a, string b) { Console.WriteLine("{0}, {1}, {2}", a == b, Object.ReferenceEquals(a, b), a.Equals(b)); } staticvoidMain(string[] args) { string s1 = "Rp3"; string s2 = "Rp3"; Usporedi(s1, s2); string s3= "Racunarski"; string s4 = s3; s3 += "praktikum 3"; // string je nepromjenjiv tip, konkatenacijom se zapravo stvara novi Usporedi(s3, s4); // string, referenca s3 se prebacuje na novi string } } True, True, True False, False, False Računarski praktikum 3
String Računarski praktikum 3
String Računarski praktikum 3
String Računarski praktikum 3