In questo periodo sto facendo molta consulenza per aziende italiane alle prese con la migrazione da VB6, usando ovviamente la versione preliminare di VB Migration Partner. Oramai la beta è stabile e si comporta davvero molto bene. In un solo giorno, ad esempio, abbiamo migrato una applicazione di circa 20mila righe che lavora in modo intensivo con ADO in circa mezza giornata, e tutto funziona a meraviglia!
Anche se la migrazione sta andando bene, a volte i programmi migrati sono più lenti del codice VB6 originario. Per esperienza le cause sono principalmente due: (1) l'uso di COM Interop per accedere agli oggetti ADO, (2) un uso massiccio di concatenazione di stringhe. Per il primo problema non c'è molto da fare, purtroppo: occorre migrare il codice di accesso al database da ADO a ADO.NET, un compito più semplice a dirsi che a farsi. Per il secondo problema ci sarebbe invece una soluzione semplice: basterebbe sostituire la variabile stringa con una variabile StringBuilder, e le concatenazioni sarebbero automaticamente più veloci. Peccato che questa sostituzione comporti una revisione completa del codice, perchè richiede di trasformare tutti gli operatori & (concatenazione) con il metodo Append, per non parlare dei casi in cui la variabile stringa viene usata come argomento a funzioni come Trim o Left. Ad esempio, il seguente codice richiede ben 17 secondi sul mio sistema a 3GHz:
Dim s As String = ""
Dim sw As Stopwatch = Stopwatch.StartNew()
For i As Integer = 1 To 100000
s = s + "*"
Next
MsgBox(sw.Elapsed.ToString)
Per fortuna la soluzione è davvero semplice: basta creare una classe che utilizzi internamente un oggetto StringBuilder, che ridefinisca gli operatori & e +, e che supporti la conversione implicita da-a stringa. Il codice di questa classe StringBuilder6 si scrive davvero in pochi minuti:
Imports System.Text
' a wrapper for the StringBuilder object, with support for + and & operators
Public Class StringBuilder6
Private buffer As New StringBuilder
' return the inner string
Public Overrides Function ToString() As String
Return buffer.ToString()
End Function
Public Shared Operator +(ByVal op1 As StringBuilder6, ByVal op2 As String) As StringBuilder6
op1.buffer.Append(op2)
Return op1
End Operator
Public Shared Operator &(ByVal op1 As StringBuilder6, ByVal op2 As String) As StringBuilder6
op1.buffer.Append(op2)
Return op1
End Operator
' convert to string
Public Shared Widening Operator CType(ByVal op As StringBuilder6) As String
Return op.ToString()
End Operator
' convert from string
Public Shared Widening Operator CType(ByVal str As String) As StringBuilder6
Dim op As New StringBuilder6()
op.buffer.Append(str)
Return op
End Operator
End Class
A questo punto per velocizzare il codice visto prima è sufficiente modificare UNA SOLA ISTRUZIONE, ovvero la dichiarazione della variabile stringa:
Dim s As StringBuilder6 = ""
Dopo questa sostituzione, il ciclo visto prima viene eseguito in 8 millesimi di secondo, ovvero circa 2000 volte più velocemente!!! Non male, per una fix così semplice
Indipendentemente dal fatto che state migrando codice da VB6 o se avete scritto codice VB.NET (o C#) da zero: se trovate dei punti in cui fate uso massiccio di concatenazione di stringhe e che pensate possano rallentare l'esecuzione, provate a sostituire la variabile stringa con un oggetto StringBuilder6: in alcuni casi il programma girerà molto ma molto più velocemente.