Antonio Feliziani
a- a+

I Generics

Spesso utilizzando il namespace System.Collections con il framework 1.0 o 1.1 abbiamo ricevuto a run-time questa eccezione :

“Unhandled Exception: System.InvalidCastException: Specified cast is not valid.”

Ricevere questo tipo di errore a run-time come tutti credo sapete, è dato da un cast sbagliato che, nella maggior parte dei casi, è legato all’utilizzo di uno degli oggetti di System.Collections.

Ogni elemento di una collection viene memorizzato come Object, di conseguenza, per inserire o recuperare un item è necessario effettuare l’unboxing o il boxing ad uno specifico tipo di dato.

Questo meccanismo è causa, non solo, di numerosi errori, ma soprattutto introduce un forte overhead e, quindi, un decadimento delle prestazioni, che è ancora più percettibile quando usiamo una collection in un ciclo.

Nel framework 2.0 questo problema è stato risolto con l’introduzione dei Generics.

I Generics sono stati introdotti con il framework 2.0 e fanno parte del namespace System.Collections.Generic, sono classi che permettono di creare tipi di dati sicuri (Type Safety) a tempo di compilazione, migliorano le prestazioni e facilitano il riutilizzo del codice.

I Generics hanno principalmente tre caratteristiche:

1. Sono Type Safety perché forzano il controllo sulla conformità del tipo (type compliance) a compile- time e non a run-time, come accadeva per System.Collections;

2. Aumentano le prestazioni perché non utilizzano il casting a run-time, poiché il tipo di dato da utilizzare viene stabilito a compile-time;

3. Favorisce il riutilizzo del codice perché sono tipi di dati parametrizzati e, quindi, è possibile usarli in più occasioni variando ogni volta il parametro.

In definitiva, con i Generics è possibile creare strutture di dati senza specificare subito il tipo di dato che verrà utilizzato. Inoltre, il namespace System.Collections.Generic mette a disposizione classi già pronte che implementano i tipi di strutture dati più comuni :

  1. Collection, equivalente generico di CollectionBase.
  2. Dictionary, equivalente generico di HashTable.
  3. LinkedList, non ha equivalente non generico.
  4. List, equivalente generico di ArrayList.
  5. Queue (FIFO), stesso nome dell'equivalente non generico.
  6. ReadOnlyCollection, equivalente generico di ReadOnlyCollectionBase.
  7. SortedDictionary, non equivalente non generico.
  8. SortedList, stesso nome dell'equivalente non generico.
  9. 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 maniera base le potenzialità dei Generics.

Premetto che userò un solo file per una vostra più facile lettura .

Form1.vb


 

Imports System.Collections

PublicClass 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.Name

            Case "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 Then

            CreateList()

       End If

       Select Case genericDataType.Name

            Case "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 - 1

            listTargetData.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.Name

            Case "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 - 1

            list.Add(CType(listSourceData.Items(i), ItemType))

       Next

   End Sub

EndClass

 

#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 Then

            Dim c As Customer

            c = CType(obj, Customer)

            If c.ID = Me.ID Then

                Return 0

            ElseIf c.ID <Me.ID Then

                Return 1

            Else

                Return -1

            End If

       Else

            ThrowNew ArgumentException("Un utente Istanza di ""Customer"" può essere comparato solo ad un'altro Customer.")

        EndIf

   End Function

   Public Property Name() As String

       Get

            Return mName

       End Get

       Set(ByVal ValueAs String)

            mName = Value

       End Set

   End Property

   Public Property ID() As Integer

       Get

            Return mId

       End Get

       Set(ByVal ValueAs Integer)

            mId = Value

       End Set

   End Property

EndClass

#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

       Get

            Return 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 Then

            Dim l As LongClass

            l = CType(obj, LongClass)

 

            If l.Value =Me.Value Then

                Return 0

            ElseIf l.Value <Me.Value Then

                Return 1

            Else

                Return -1

            End If

       Else

            ThrowNew ArgumentException("Un Numero istanza di ""LongClass"" può essere comparato solo ad un'altro LongClass.")

        EndIf

   End Function

EndClass

#EndRegion

Grazie ai 'Generics' lavoriamo con il tipo usato nella dichiarazione quindi il casting non è più necessario e allo stesso tempo possiamo finalmente creare del codice realmente riutilizzabile per un'infinità di situazioni senza correre il rischio di lasciare qualcosa di errato in giro perchè il compilatore è in grado di avvertirci quando qualcosa non va.
 



Ti potrebbe interessare anche

commenta la notizia

C'è 1 commento
Staff
Ti interessano altri articoli su questo argomento?
Chiedi alla nostra Redazione!