liste e generics - www3

Transcript

liste e generics - www3
Listee generics (C#)
Vittorio Maniezzo
Università di Bologna
I generici
I generics sono una funzionalità della versione 2.0 del linguaggio
C# (e del CLR).
Introducono il concetto di parametri di tipo, grazie ai quali è
possibile progettare classi e metodi che rinviano la specifica di
uno più tipi fino a quando un codice che li utilizza non ne
dichiara o crea un'istanza.
I generics rappresentano la soluzione a una limitazione presente
nelle versioni precedenti di CLR e C#, in cui la generalizzazione
viene effettuata mediante il cast di tipi in e dal tipo base
universale Object.
Una classe generica consente invece di creare un insieme
indipendente dai tipi in fase di compilazione.
Vittorio Maniezzo – Università di Bologna
2
Array
Gli array sono i più semplici contenitori di dati predefiniti in C#.
Hanno più funzionalità degli array in C / C++, ma restano poco
adatti per ricerche e modifiche strutturali.
Esempio: incrementare la dimensione di un array per metterci
Pippo.
string [] newArray = new string[array.Length+1];
for (int i=0; i<array.Length; i++)
newArray[i] = array[i];
Dovrebbe essere
newArray[newArray.Length] = “Pippo";
newArray.Length-1
array = newArray;
Dov’è l’errore?
Vittorio Maniezzo – Università di Bologna
3
Generici
• Il C# può utilizzare strutture dati simili agli STL
containers del C++.
• Il C# le chiama generics (generici), dato che possono
contenere dati di un qualunque tipo.
• I generici sono definiti nella libreria
System.CoIIections.Generics, che è referenziata
automaticamente per i nuovi progetti.
• L’uso è uguale al C++, ma i nomi sono diversi.
Vittorio Maniezzo – Università di Bologna
4
Generici
List
dynamic array
C++ STL
container
vector
SortedList
binary tree
set
Dictionary
hash table
map
LinkedList
linked list
list
Queue
queue
queue
Stack
stack
stack
C# Generic
Data Structure
In C# in più c’è anche un generico che si chiama
SortedDictionary, è un ibrido fra una hash table e un binary
tree.
Vittorio Maniezzo – Università di Bologna
5
Il generico List
La classe List è un array dinamico.
Viene istanziata con il comando new, come qualunque altro
oggetto
Come in C++, il tipo viene definito fra <parentesi angolari>.
List<string> words = new List<string>();
List<Employee> staff = new List<Employee>();
Senza il comando new non si compila!
List<string> words; //Errore!
Come con i vettori, si può definire la dimenzione iniziale.
List<string> words = new List<string>(100);
Come con i vettori, è possibile accedere agli elementi con [].
words[3] = “Pippo";
Vittorio Maniezzo – Università di Bologna
6
Variazioni di una lista
Si inseriscono elementi con il comando Add().
words.Add(“Pippo");
staff.Add(new Employee(“Pippo“, 23432));
Il comando Remove(object) cerca l’oggetto passato come
parametro e lo cancella dalla lista.
words.Remove(“Pippo");
Employee pippo = new Employee(“Pippo",23432.88);
staff.Remove(pippo);
Il comando RemoveAt(int) elimina l’elemento nella posizione
specificata.
words.RemoveAt(0);
// Elimina il primo elemento.
words.RemoveAt(words.Count-1); // elimina l’ultimo.
Il comando Clear() elimina tutti gli elementi di una lista.
words.Clear();
Vittorio Maniezzo – Università di Bologna
7
Ricerca in una lista
Ci sono molte funzioni per ricercare in una lista. La più
semplice è Contains(object).
bool ListName.Contains( object )
Ritorna true se l’oggetto dato è nella lista.
If (words.Contains(“Pippo"))
Console.WriteLine(“Pippo è nella lista.");
Bisogna fare attenzione nell’utilizzo: controlla la
presenza dell’oggetto (l’indirizzo di memoria deve
combaciare).
Vittorio Maniezzo – Università di Bologna
8
Predicati
Un predicato è una funzione booleana che accetta un parametro
tipizzato (stesso tipo di quello della List).
La funzione Find prende in input il nome del predicato.
Es. Trova tutti gli studenti il cui nome comincia con M.
static bool StartsWithM (string s)
{ return (s[O] == 'M’);
}
Ora, avendo una lista dei nomi degli studenti.
List<string> names = new List<string>(5);
Una chiamata alla funzione Find ritorna il primo studente nella
lista per cui il predicato ritorna true.
string firstMName = names.Find(StartsWithM);
Per avere l’ultimo si usa FindLast.
Vittorio Maniezzo – Università di Bologna
9
Funzioni di ricerca
Ci sono diverse funzioni di ricerca basate su predicati.
Exists(predicate) ritorna true se il predicato è soddisfatto per
qualche elemento.
if (names.Exists(StartsWithM))
Console.WriteLine("Somebody starts with a M.");
RemoveAlI(predicate) cancella ogni elemento per cui il predicato
ritorna true.
names.RemoveAll(StartsWithM);
FindAll(predicate) riturna una lista con tutti gli elementi per cui il
predicato è vero.
List<string> names2 = names.FindAll(StartsWithM);
foreach (string s in names2) //Nota: foreach è
applicabile al tipo List
Console.WriteLine(s);
Vittorio Maniezzo – Università di Bologna
10
Ordinamento di una lista
La funzione Sort assume che sia definito l’operatore < per gli
oggetti da ordinare.
names.Sort();
//Ordina le stringhe alfabeticamente.
Si può anche fornire un predicato alla funzione Sort per far
ordinare in qualche modo specifico.
Es., predicato che prende in input due item e ritorna un int
int comparison (T x, T y)
return 0 if x == y, return -1 if x<y, return 1 if x>y
Esempio: che ordinamento è questo?
names.Sort(nomi);
static int nomi(string s1, string s2)
{ if (s1.Length < s2.Length) return 1;
if (s1.Length > s2.Length) return -1;
else return 0;
}
Vittorio Maniezzo – Università di Bologna
11
Il generico Dictionary
Dictionary è una hash table (map).
Memorizza un dato e la sua chiave.
Per dichiarare un Dictionary, si specifica il tipo della
chiave e il tipo del dato.
Dictionary<int,string> words = new
Dictionary<int,string>();
Dictionary<string, Employee> staff = new
Dictionary<string, Employee> ();
Tutte le chiavi in un Dictionary devono essere uniche.
Vittorio Maniezzo – Università di Bologna
12
Dictionary Functions
Per aggiungere nuovi elementi al Dictionary, si specificano chiave e
dato.
staff.Add(“Pippo", new Employee(“Pippo Goofy", 23883));
Si può cercare o aggiungere elementi usando le parentesi quadre
sul tipo della chiave.
Employee pippo = staff[“Pippo"];
staff[“Pluto"] = new EmpIoyee(“Pluto Topolino”, 1000000);
Si può cercare un elemento nel dizionario sia con la chiave che con
il valore del dato.
if (staff.ContainsKey(“Pippo"))
Console.WriteLine(“Ho trovato Pippo.");
Employee pluto = new EmpIoyee(“Pluto Topolino”, 1000000);
if (staff.ContainsValue(pluto))
Console.WriteLine(“Ho trovato Pluto.");
Vittorio Maniezzo – Università di Bologna
13
Il generico Stack
Stack
Push(T)
T Pop()
T Peek()
– struttura dati LIFO
– mette un elemento in cima allo stack
– toglie l’elemento in cima e lo ritorna
– ritorna l’elemento in cima senza toglierlo
Esempio:
Stack<string> s = new Stack<string>();
s.Push(“Pippo");
s.Push(“Pluto");
s.Push(s.Pop());
Console.WriteLine( s.Peek() + s.Pop() + s.Peek() );
Vittorio Maniezzo – Università di Bologna
14
Il generico Queue
Queue
– struttura dati FIFO
Enqueue(T) – nuovo elemento accodato
T Dequeue()– elimina il primo elemento della coda e lo ritorna
T Peek()
– ritorna il primo elemento della coda senza eliminarlo
Esempio:
Queue<string> q = new Queue<string>();
q.Enqueue(“Pippo");
q.Enqueue(“Pluto");
q.Enqueue(q.Dequeue);
Console.WriteLine(q.Peek());
Vittorio Maniezzo – Università di Bologna
15
Generici fai da te
// Dichiara la classe generica
public class GenericList<T>
{ void Add(T input) { }
}
class TestGenericList
{
static void Main()
{ // Dichiara una lista di tipo int
GenericList<int> list1 = new GenericList<int>();
// Dichiara una lista di tipo string
GenericList<string> list2 = new GenericList<string>();
}
}
Vittorio Maniezzo – Università di Bologna
16
Delegate generici
delegate bool Check<T>(T value);
class Payment
{ public DateTime date;
public int amount;
}
internal class Account
{ private IList<Payment> payments = new List<Payment >();
public void Add(Payment p)
{ payments.Add(p); }
public int AmountPayed( Check<Payment> matches )
{ int val = 0;
foreach (Payment p in payments)
if ( matches(p) ) val += p.amount;
Si passa il metodo
return val;
check, che controlla
}
se i pagamenti sono
}
accetabili
Vittorio Maniezzo – Università di Bologna
17
Riassumendo
(cfr. MSDN)
• Utilizzare i tipi generici per massimizzare il riutilizzo del codice,
l'indipendenza dai tipi e le prestazioni.
• I generics vengono generalmente utilizzati per creare classi di
insiemi.
• La libreria di classi .NET Framework contiene diverse classi di
insiemi generiche nello spazio dei nomi
System.Collections.Generic.
• È possibile creare interfacce, classi, metodi, eventi e delegati
generici personalizzati.
• Le classi generiche possono essere vincolate in modo da
consentire l'accesso ai metodi su solo determinati tipi di dati.
• È possibile ottenere informazioni sui tipi utilizzati in un tipo di
dati generico in fase di esecuzione tramite la reflection.
Vittorio Maniezzo – Università di Bologna
18