- Visual Basic .Net: come ottenere le
stesse prestazioni di C# -
|
|||
COSA SERVE PER QUESTO TUTORIAL | |||
Download | Chiedi sul FORUM | Glossario | conoscenza base di VB .Net | ||
Considerazioni su sintassi, late-binding, cast e controllo degli overflow in VB .Net | |||
PREGI E DIFETTI DI VISUAL BASIC La sintassi di VB. Spesso si sente parlare male di VB .Net e al suo posto suggeriscono l'uso di C#. Ebbene sotto certi aspetti VB .Net è del tutto equivalente a C#, sotto altri inferiore, sotto altri ancora è persino superiore. Trascurando i semplici fattori di gusto è innegabile che la sintassi di Visual Basic sia chiara, semplice, intuitiva e quasi paragonabile a pseudo-codice (ovvero comprensibile da chiunque abbia una minima cognizione di programmazione). In alcuni contesti risulta anche molto più chiara, in particolare in ASP .Net dove spesso ci si trova a mischiare codice HTML e linguaggio .Net; si pensi ad un codice molto articolato, ricco di condizioni If, cicli e altro ancora: nei linguaggi C-like (quale C# è) non è facilmente intuibile a cosa si riferisca una chiusa graffa ("}"), se non grazie all'indentazione e comunque in presenza nella stessa schermata dell'inizio del blocco. Si tratta del termine di un ciclo? Di un If? In Visual Basic questo problema viene risolto costringendo chi scrive il codice ad esplicitare che cosa si sta chiudendo (End If, Loop, End Sub e così via), inoltre chiudendo un ciclo For è anche possibile specificare la variabile su cui si sta ciclando, il che rende possibile distinguere facilmente dove ci si trova se si è in presenza di più cicli nestati (uno dentro all'altro). For CUtenti As Integer = 1 To 10 [...] For CFigli As Integer = 1 To 3 [...] Next CFigli [...] Next CUtenti
Certamente la sintassi Basic è estremamente prolissa, ma con i
moderni ambienti di sviluppo questo problema non tocca molto chi scrive
codice, grazie a funzionalità di auto-completamento e simili. Gli svantaggi pratici e teorici di un uso indiscriminato del late-binding. Il late-binding consiste in sostanza nella possibilità di effettuare chiamate "alla cieca", ovvero ad esempio chiamare su una variabile dichiarata come Object il metodo Clear(). Questo metodo ovviamente non appartiene alla classe Object, ma, se il late-binding è abilitato questo fatto non darà errore fino all'esecuzione della riga in questione e non lo darà neppure allora se quella variabile contiene in realtà una oggetto ad esempio di tipo DataTable. Chiariamo il concetto con un esempio: Dim obj As Object obj = New System.Data.DataTable() obj.Clear() L'esempio sopra è del tutto lecito, in quanto a run-time il CLR andrà a verificare se l'oggetto obj dispone del metodo e lo chiamerà. Tuttavia questa verifica a run-time richiede un notevole (ed inutile) dispendio di risorse, che possiamo quantificare approssimativamente con le seguenti righe di codice: Sub Main() Console.WriteLine("Attendere 20 secondi.") Dim lngCountLB As Long = 0, lngCountNotLB As Long = 0 Dim dtStop As DateTime dtStop = Now.AddSeconds(10) Dim objDT As Object objDT = New System.Data.DataTable() Do While Now < dtStop objDT.Clear() lngCountLB += 1 Loop dtStop = Now.AddSeconds(10) Dim dtDT As System.Data.DataTable dtDT = New System.Data.DataTable() Do While Now < dtStop dtDT.Clear() lngCountNotLB += 1 Loop Console.WriteLine("Operazioni in late binding: " & lngCountLB) Console.WriteLine("Operazioni senza late binding: " & lngCountNotLB) Console.WriteLine("In assenza di late binding vengono eseguite {0} volte più operazioni.", _ Math.Round(lngCountNotLB / lngCountLB, 2)) Console.ReadLine() End Sub Il codice presentato non fa altro che misurare quante volte in 10
secondi viene chiamato il metodo Clear() su un DataTable definito come
Object (quindi servendosi del late-binding) e quante con una variabile
con tipizzazione forte (ovvero dichiarata direttamente come DataTable). Per rendere
l'idea, sulla macchina su cui è stato testato il metodo senza
late-binding è risultato dalle 8 alle 10 volte più veloce. Non è di
certo un risultato trascurabile. Option Strict On O anche a livello di progetto andando sulle opzioni di compilazione
ed impostando la casella Option Strict anche qui su On. O ancora da
linea di comando specificando il parametro "/optionstrict+" al
compilatore di Visual Basic (vbc.exe). Per ASP .Net si può impostare per
tutta l'applicazione tramite l'elemento compilation (all'interno della
sezione system.web), impostando l'attributo strict su true oppure,
in una pagina specifica, nella
direttiva Page, sempre impostando l'attributo strict su true. Dim strStringa As String = 123 Questo perché implicitamente (con Option Strict disattivato) avverrebbe un cast su 123 dal tipo Integer a String. Sebbene questa restrizione possa inizialmente apparire fastidiosa, col tempo si rivela utile nell'evitare errori difficoltosi da individuare. La linea corretta dovrebbe essere quindi: Dim strStringa As String = CStr(123)I CAST Conoscere quale tipo di cast usare per ottimizzare le prestazioni. Il secondo punto a cui bisogna prestare attenzione è l'uso dei cast. In generale per effettuare cast verso tipi semplici come String, Integer, Double e così via è buona praticata usare le corrispettive parole chiave: CStr, CInt, CDbl e così via. Ad esempio: Dim bln As Boolean = CBool("true") Dim byt As Byte = CByte("12") Dim chr As Char = CChar("x") Dim dat As Date = CDate("1/1/1950") Dim dbl As Double = CDbl("3,14") Dim dec As Decimal = CDec("79228162514264337593543950335") Dim int As Integer = CInt("23498") Dim lng As Long = CLng("23874089") Dim obj As Object = CObj("Sono un oggetto.") Dim sbyt As SByte = CSByte("-123") Dim shr As Short = CShort("44") Dim sng As Single = CSng("6,28") Dim str As String = CStr(123) Dim uint As UInteger = CUInt("442") Dim ushr As UShort = CUShort("77") Per le conversioni da un tipo complesso ad un altro si deve invece usare CType o DirectCast a seconda delle evenienze. CType tenta sempre di effettuare una conversione, ad esempio dalla stringa "123" al corrispondente valore Integer, al contrario DirectCast non esegue conversioni ma semplicemente cambia il tipo, se possibile, ovvero quando l'oggetto su cui si sta effettuando il cast eredita o è il tipo di destinazione. Immaginiamo di avere la seguente Sub: Sub Elabora(Input As Object, TipoDiInput As Integer) Select Case TipoDiInput Case 1 'DataTable Dim dt As DataTable dt = DirectCast(Input, Data.DataTable) 'Elabora la DataTable Case 2 'String Dim str As String str = DirectCast(Input, String) 'Elabora la stringa Case 3 'Integer Dim int As Integer int = DirectCast(Input, Integer) 'Elabora il numero End Select End Sub Nota: questo codice è solo a scopo esemplificativo della funzione di DirectCast, una routine simile è una pessima tecnica di programmazione, per ottenere lo stesso risultato in maniera pulita si dovrebbero scrivere tre overload della funzione che prendono un solo parametro di tipo diverso (DataTable, String e Integer). La funzione in questione effettua un cast su un parametro generico di
tipo Object verso un tipo suggerito dal secondo parametro, ma senza
effettuare alcuna conversione sui dati, semplicemente esplicita (espone)
il tipo di Input che era "nascosto" all'interno della variabile di tipo
Object. Dim int As Integer = DirectCast("123", Integer) Ma funzionerebbero le seguenti: Dim dt As New Data.DataTable() Dim obj As Object obj = dt Dim dt2 As Data.DataTable dt2 = DirectCast(obj, Data.DataTable) Infatti la variabile obj contiene in realtà una DataTable e riconvertirla al suo tipo originario non richiede alcuna conversione. In questo caso utilizzare CType sarebbe stato meno efficiente, per questo è importante capire quando è necessario utilizzare l'uno o l'altro operatore. IL CONTROLLO SULL'OVERFLOW DEGLI INTERI L'ultimo punto a cui prestare attenzione per avere prestazioni equivalenti a C# è il controllo dell'overflow degli interi. Consideriamo la seguente linea di codice: Dim int As Integer = Integer.MaxValue + 1 Visual Basic, di default, esegue un controllo di overflow degli
interi, ovvero quella riga darebbe errore poiché si sta tentando di
sommare un unità al massimo numero che un Integer può contenere. 'Possono avere accesso solo le persone con 'un nome e cognome lungo meno di 30 caratteri Dim intLunghezzaNome As UInteger Dim intLunghezzaCognome As UInteger Console.Write("Quanti caratteri compongono il tuo nome? ") intLunghezzaNome = CUInt(Console.ReadLine()) Console.Write("Quanti caratteri compongono il tuo cognome? ") intLunghezzaCognome = CUInt(Console.ReadLine()) If intLunghezzaNome + intLunghezzaCognome < 30 Then Console.WriteLine("Accesso accordato.") Else Console.WriteLine("Accesso negato.") End If
Se l'utente inserisse ad esempio 12 per il nome e 4294967295 (o comunque
il valore UInteger.MaxValue) la somma dei due valori darebbe 11, poiché
l'overflow della somma porterebbe dal valore massimo al valore minimo (0
per un UInteger) e quindi a crescere fino a 11. In questo caso
basterebbe semplicemente imporre restrizioni sull'input dell'utente, ma
altri casi possono essere molto più articolati e non verranno
approfonditi in questo articolo.
|
|||
<< INDIETRO | by VeNoM00 |