I Generics
Spesso utilizzando il namespace System.Collections con ilframework 1.0 o 1.1 abbiamo ricevuto a run-time questaeccezione :
“Unhandled Exception: System.InvalidCastException:Specified cast is not valid.”
Ricevere questo tipo di errore a run-time come tutti credosapete, è dato da un cast sbagliato che, nella maggiorparte dei casi, è legato all’utilizzo di unodegli oggetti di System.Collections.
Ogni elemento di una collection viene memorizzato comeObject, di conseguenza, per inserire o recuperare un itemè necessario effettuare l’unboxing o il boxingad uno specifico tipo di dato.
Questo meccanismo è causa, non solo, di numerosierrori, ma soprattutto introduce un forte overhead e, quindi,un decadimento delle prestazioni, che è ancorapiù percettibile quando usiamo una collection in unciclo.
Nel framework 2.0 questo problema è stato risolto conl’introduzione dei Generics.
I Generics sono stati introdotti con il framework 2.0 efanno parte del namespace System.Collections.Generic, sonoclassi che permettono di creare tipi di dati sicuri (TypeSafety) a tempo di compilazione, migliorano le prestazioni efacilitano il riutilizzo del codice.
I Generics hanno principalmente tre caratteristiche:
1. Sono Type Safety perché forzano il controllo sullaconformità del tipo (type compliance) a compile- timee non a run-time, come accadeva per System.Collections;
2. Aumentano le prestazioni perché non utilizzano ilcasting a run-time, poiché il tipo di dato dautilizzare viene stabilito a compile-time;
3. Favorisce il riutilizzo del codice perché sono tipidi dati parametrizzati e, quindi, è possibile usarliin più occasioni variando ogni volta il parametro.
In definitiva, con i Generics è possibile crearestrutture di dati senza specificare subito il tipo di datoche verrà utilizzato. Inoltre, il namespaceSystem.Collections.Generic mette a disposizione classigià pronte che implementano i tipi di strutture datipiù comuni :
- Collection, equivalente generico di CollectionBase.
- Dictionary, equivalente generico di HashTable.
- LinkedList, non ha equivalente non generico.
- List, equivalente generico di ArrayList.
- Queue (FIFO), stesso nome dell'equivalente non generico.
- ReadOnlyCollection, equivalente generico di ReadOnlyCollectionBase.
- SortedDictionary, non equivalente non generico.
- SortedList, stesso nome dell'equivalente non generico.
- Stack (LIFO), stesso nome dell'equivalente non generico.
Ad esempio portiamo un classico “Sort”
Prima di tutto creiamo un form.
E a questo punto possiamo andare a sperimentare in manierabase le potenzialità dei Generics.
Premetto che userò un solo file per una vostrapiù facile lettura .
Form1.vb
Imports System.CollectionsPublicClass Generics Dim genericDataType As Type Dim stringList As List(Of String) Dim longList As List(Of LongClass) Dim customerList As List(Of Customer) Private Sub btnSort_Click(ByVal senderAs System.Object, ByVal e As System.EventArgs) Handles btnSort.Click listTargetData.Items.Clear() SortList() End Sub Private Sub SortList() Select Case genericDataType.NameCase "String" ListSort(stringList)Case "LongClass" ListSort(longList)Case "Customer" ListSort(customerList) End Select LoadList(False) End Sub Private Sub ListSort(Of ItemType)(ByVal list As List(Of ItemType)) list.Sort() End Sub Private Sub LoadList(Optional ByVal recreate As Boolean = True) If recreate ThenCreateList() End If Select Case genericDataType.NameCase "String" ListDisplay(stringList)Case "LongClass" ListDisplay(longList)Case "Customer" ListDisplay(customerList) End Select End Sub Private Sub ListDisplay(Of ItemType)(ByVal list As List(Of ItemType)) For i AsInteger = 0 To list.Count - 1listTargetData.Items.Add(list(i)) Next End Sub #Region"Assegno i valori" Private Sub btnObject_Click(ByVal senderAs System.Object, ByVal e As System.EventArgs) Handles btnObject.Click listSourceData.Items.Clear() listTargetData.Items.Clear() Dim c As Customer c = New Customer("Antonio Feliziani" , 1) listSourceData.Items.Add(c) c = New Customer("Lorenzo Pascucci" , 2) listSourceData.Items.Add(c) c = New Customer("Sara Bianchi" , 3) listSourceData.Items.Add(c) c = New Customer("Ivo Marzetti" , 4) listSourceData.Items.Add(c) c = New Customer("Daniele Rossi" , 5) listSourceData.Items.Add(c) genericDataType = GetType(Customer) CreateList() End Sub Private Sub btnLong_Click(ByVal senderAs System.Object, ByVal e As System.EventArgs) Handles btnLong.Click listSourceData.Items.Clear() listTargetData.Items.Clear() Dim l As LongClass l = New LongClass(6) listSourceData.Items.Add(l) l = New LongClass(447) listSourceData.Items.Add(l) l = New LongClass(780812) listSourceData.Items.Add(l) l = New LongClass(99) listSourceData.Items.Add(l) l = New LongClass(-1) listSourceData.Items.Add(l) genericDataType = GetType(LongClass) CreateList() End Sub Private Sub btnString_Click(ByVal senderAs System.Object, ByVal e As System.EventArgs) Handles btnString.Click listSourceData.Items.Clear() listTargetData.Items.Clear() listSourceData.Items.Add("Daniela Verdi") listSourceData.Items.Add("Emauele Gistra") listSourceData.Items.Add("Pino Menichelli") listSourceData.Items.Add("Massimo Neri") listSourceData.Items.Add("Sandro Castelli") genericDataType = GetType(String) CreateList() End Sub#EndRegion Private Sub CreateList() Select Case genericDataType.NameCase "String" stringList = New System.Collections.Generic.List(OfString) ListAdd(stringList)Case "LongClass" longList = New System.Collections.Generic.List(Of LongClass) ListAdd(longList)Case "Customer" customerList = New System.Collections.Generic.List(Of Customer) ListAdd(customerList) End Select End Sub Private Sub ListAdd(Of ItemType)(ByVal list As List(Of ItemType)) For i AsInteger = 0 To listSourceData.Items.Count - 1list.Add(CType(listSourceData.Items(i), ItemType)) Next End SubEndClass #Region"Class Customer" PublicClass Customer Implements IComparable Private mName AsString Private mId AsInteger Public SubNew(ByVal new_name As String,ByVal new_id AsInteger) mName = new_name mId = new_id End Sub Public OverridesFunction ToString() AsString Return mId.ToString() + ": " + mName End Function Public Function CompareTo(ByVal obj AsObject) AsInteger Implements IComparable.CompareTo If TypeOf objIs Customer ThenDim c As Customerc = CType(obj, Customer)If c.ID = Me.ID Then Return 0ElseIf c.ID <Me.ID Then Return 1Else Return -1End If ElseThrowNew ArgumentException("Un utente Istanza di ""Customer"" può essere comparato solo ad un'altro Customer.") EndIf End Function Public Property Name() As String GetReturn mName End Get Set(ByVal ValueAs String)mName = Value End Set End Property Public Property ID() As Integer GetReturn mId End Get Set(ByVal ValueAs Integer)mId = Value End Set End PropertyEndClass#EndRegion #Region"Class LongClass" PublicClass LongClass Implements IComparable Public SubNew(ByVal lAs Long) v = l End Sub Private v AsLong Public Property Value() As Long GetReturn v End Get Set(ByVal ValueAs Long)v = Value End Set End Property Public OverridesFunction ToString() AsString Return v.ToString() End Function Public Function CompareTo(ByVal obj AsObject) AsInteger Implements IComparable.CompareTo If TypeOf objIs LongClass ThenDim l As LongClassl = CType(obj, LongClass) If l.Value =Me.Value Then Return 0ElseIf l.Value <Me.Value Then Return 1Else Return -1End If ElseThrowNew ArgumentException("Un Numero istanza di ""LongClass"" può essere comparato solo ad un'altro LongClass.") EndIf End FunctionEndClass#EndRegion Grazie ai 'Generics' lavoriamo con il tipo usatonella dichiarazione quindi il casting non è piùnecessario e allo stesso tempo possiamo finalmente creare delcodice realmente riutilizzabile per un'infinità disituazioni senza correre il rischio di lasciare qualcosa dierrato in giro perchè il compilatore è in gradodi avvertirci quando qualcosa non va.
