Transmutación de código VB6 a lenguajes .NET

Manifiesto de una traducción formal desde una clase VB6 hacia clases VB .NET y C#

Por Harvey Triana

Descarga Descargar Ejemplo de este artículo.

Contenido

 1. Introducción
 2. El clásico utilitario números a letras
 3. Solución en VB .NET
 4. Traducción eficiente desde VB6 hacia VB .NET
 5. Probando la clase CN2W de VB .NET
 6. Solución en C#
 7. Probando la clase CN2W de C#
 8. Conclusión

1. Introducción

Muchas veces me he preguntado si existe alguien que realmente programe VB .NET puro. Sabemos que VB .NET no es una metamorfosis de VB, sino una especificación nueva derivada de otro lenguaje: C#. ¿Es justo que, por un puñado de palabras reservadas, llamemos Visual Basic a VB .NET? Seamos realistas: las dos primeras palabras de VB .NET no son más que una mera etiqueta. Pero esto no es dramático; no tengo el propósito de polemizar. VB .NET es un buen lenguaje, y muy elegante.

Percibo que VB .NET puro está sometido a un segundo plano por C#. La gran mayoría de los ejemplos de VB .NET que encuentras están escritos por programadores C#, para programadores C#, y traducidos a VB .NET por un tonto robot. Esto deslegitima aún más a VB .NET como familia de VB. Por otra parte, mucho código de VB .NET, en especial el de los programadores emigrantes desde VB6, usa el espacio de nombres Microsoft.VisualBasic; y éstos creen erróneamente que están produciendo código VB .NET. Esto último es una cuestión a la que naturalmente huyen los programadores puristas de lenguajes .NET.

Pero entonces ¿A qué deberían aspirar los programadores de Visual Basic clásico? El objetivo de este artículo es tomar una buena clase de VB6, traducirla a VB .NET puro (sin el espacio de nombres Microsoft.VisualBasic), y luego a C#. Quizás te sorprendas de la similitud de VB .NET con C# cuando programemos VB .NET puro, y la gran distancia que hay entre VB6 y VB .NET.

Mucho se ha escrito acerca de la migración de VB6 hacia VB .NET; no obstante, me pregunto si se estará orientando bien a los programadores VB6. Quizás sería preferible olvidarse de que existe VB .NET y comenzar con C#.

 

2. El clásico utilitario números a letras

Imagino que, por su utilidad, el problema de traducir una cifra de números en letras es tratado desde que existe la programación. La solución del problema es un buen ejercicio para todos los programadores dedicados. En este artículo trataremos este problema en su versión en inglés. Escogí la versión en inglés porque el código es más corto y tiene una lógica más simple de seguir en cuanto a propósitos didácticos.

Cuando abordé este problema, cumplí con los siguientes objetivos:

  1. Convertir una cifra entera, de números a letras.

  2. Traducir una cifra real, de números a letras.

  3. Traducir una cantidad monetaria, de signos y números a letras; por ejemplo, el número 123.456 debe producir la siguiente salida:

    Función Respuesta
    Moneda a Letras One Hundred Twenty Three Dolars And Forty Six Cents
    Real a Letras One Hundred Twenty Three Dot Four Hundred Fifty Six
    Entero a Letras One Hundred Twenty Three

Básicamente se trata de una sola función, la cual convierte un número entero en letras; las demás son derivadas de la misma, con ciertos detalles. A los fines de este artículo he creado 3 clases: la primera en VB6, la segunda en VB .NET, y la tercera en C#.

 

3. Solución en VB .NET

En un principio podría haber tomado la clase escrita en VB6, importado la librería Microsoft.VisualBasic, y pegado código. Con unos cuantos ajustes podría hacer funcionar esto en VB .NET. Con esa estrategia en mente, voy a producir un código VB .NET sucio y poco didáctico a la hora de aprovechar el potencial real de VB .NET. Tampoco voy a ser honesto con la eficiencia, ya que voy a colocar una capa de software delante de VB .NET para hacer funcionar mi código. Si vamos a programar formalmente en un lenguaje .NET deberíamos evitar el espacio de nombres Microsoft.VisualBasic.

Usar el espacio de nombres Microsoft.VisualBasic es como si, por alguna razón de logística, un programador VB .NET que nunca ha escrito VB6 tuviera que programar en VB6. Al desconocer VB6, le parecerían extrañas funciones tales como Left$(), Right$() ó Mid$(). Posiblemente optaría por crear una clase Global Multiuse con un método SubString() - si fuera más osado tal vez crearía una clase StringVBNET y se ahorraría el análisis. No obstante, estaría subutilizando VB6 ya que al colocar una capa de software delante de VB6 para que su código funcione, estaría omitiendo las funciones de la especificación VB6, y obligaría al modulo de ejecución de VB6 a hacer trabajo extra. Esta analogía es equivalente al programador VB .NET que usa el espacio de nombres Microsoft.VisualBasic para migrar un código de VB6 a VB .NET.

El código que se muestra a continuación es VB .NET puro. Incluso la función IsNumeric fue reemplazada por unas líneas muy eficientes:

Option Strict On '//required if we desired traslate to C#
 
Imports System.Globalization
 
Public Class CN2W
 
Private Const ZERO As String = "Zero"
 
Private IntegerPart As String = ZERO
Private RealPart As String = ZERO
 
Private m_DecimalSeparator As String
Private m_GroupSeparator As String
 
Private aT0() As String = {"One", "Two", "Three", "Four", "Five", "Six", "Seven",  "Eight", "Nine"}
Private aT1() As String = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen",
 "Eighteen", "Nineteen"}
Private aT2() As String = {"Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}
Private aT3() As String = {"", "", " Thousand ", " Million ", " Billion ", " Trillion ", "", "", "", ""}
 
Public Sub New()
    m_DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator
    m_GroupSeparator = CultureInfo.CurrentCulture.NumberFormat.CurrencyGroupSeparator
End Sub
 
Public Function IntegerToWords(ByVal Number As String) As String
    Call RealToWords(Number)
    Return IntegerPart
End Function
 
Public Function RealToWords(ByVal Number As String) As String
    Dim DotPos As Integer = 0
    IntegerPart = ZERO
    RealPart = ZERO
    If IsNumeric(Number) Then
        Number = Number.Replace(m_GroupSeparator, "")
        DotPos = Number.IndexOf(DecimalSeparator)
        If DotPos >= 0 Then
            IntegerPart = ToWords(Convert.ToInt32(Number.Substring(0, DotPos)))
            RealPart = ToWords(Convert.ToInt32(Number.Substring(DotPos + 1, Number.Length - DotPos - 1)))
        Else
            IntegerPart = ToWords(Convert.ToInt32(Number))
        End If
    End If
    Return IntegerPart & " Dot " & RealPart
End Function
 
Public Function CurrencyToWords(ByVal Number As String, ByVal MoneyName As String) As String
 
    Dim s As String = ""
 
    IntegerPart = ZERO
    RealPart = ZERO
 
    If IsNumeric(Number) Then
        ' round to money number
        s = RealToWords(RoundNumberString(Convert.ToDouble(Number), 2))
    End If
    ' add money text
    If IntegerPart = ZERO Then IntegerPart = "No"
    Select Case RealPart
        Case ZERO : RealPart = "And No Cents"
        Case "One" : RealPart = "And One Cent"
        Case Else : RealPart = "And " & RealPart & " Cents"
    End Select
    Return IntegerPart & " " & MoneyName & " " & RealPart
End Function
 
Private Function ToWords(ByVal Number As Integer) As String
    Dim s As String = ""
    Dim d As String = ""
    Dim r As String = ""
    Dim n As Integer = 0
 
    s = Number.ToString
    n = 1
    Do Until s.Length = 0
        ' convert last 3 digits of s to english words
        If s.Length < 3 Then
            d = ConvertHundreds(s)
        Else
            d = ConvertHundreds(s.Substring(s.Length - 3, 3))
        End If
        If d.Length > 0 Then r = d & aT3(n) & r
        If s.Length > 3 Then
            ' remove last 3 converted digits from s.
            s = s.Substring(0, s.Length - 3)
        Else
            s = ""
        End If
        n += 1
    Loop
    If r.Length = 0 Then r = ZERO
    Return r.Trim
End Function
 
Private Function ConvertHundreds(ByVal pNumber As String) As String
    Dim rtn As String = ""
 
    If Not Convert.ToInt32(pNumber) = 0 Then
        ' append leading zeros to number.
        pNumber = ("000" & pNumber).Substring(pNumber.Length, 3)
        ' do we have a hundreds place digit to convert?
        If Not pNumber.Substring(0, 1) = "0" Then
            rtn = ConvertDigit(pNumber.Substring(0, 1)) & " Hundred "
        End If
        ' do we have a tens place digit to convert?
        If pNumber.Length >= 2 Then
            If Not pNumber.Substring(1, 1) = "0" Then
                rtn &= ConvertTens(pNumber.Substring(1))
            Else
                rtn &= ConvertDigit(pNumber.Substring(2))
            End If
        End If
        Return rtn.Trim
    Else
        Return ""
    End If
End Function
 
Private Function ConvertTens(ByVal pTens As String) As String
    Dim r As String = ""
    ' is value between 10 and 19?
    If Convert.ToInt32(pTens.Substring(0, 1)) = 1 Then
        r = aT1(Convert.ToInt32(pTens) - 10)
    Else
        ' otherwise it's between 20 and 99.
        r = aT2(Convert.ToInt32(pTens.Substring(0, 1)) - 2) & " "
        ' convert ones place digit
        r &= ConvertDigit(pTens.Substring(pTens.Length - 1, 1))
    End If
    Return r
End Function
 
Private Function ConvertDigit(ByVal pNumber As String) As String
    If pNumber = "0" Then
        Return ""
    Else
        Return aT0(Convert.ToInt32(pNumber) - 1)
    End If
End Function
 
Private Function RoundNumberString(ByVal Number As Double, ByVal Decimals As Integer) As String
   
    Dim s As String
    Dim r As Double
 
    ' round first
    r = 10 ^ Decimals
    ' Math.Floor make sure the float round. Suggested by Guillermo Som
    r = CType(Math.Floor(Number * r + 0.5), Integer) / r
    ' complete with zeros
    s = r.ToString
    If s.IndexOf(".") < 0 Then s &= "."
    Do While s.Substring(s.IndexOf(".")).Length <= Decimals
        s &= "0"
    Loop
    Return s
End Function
 
'/ Source: http://aspalliance.com/articleViewer.aspx?aId=80&pId=
'/ Traslate and review to VB.NET by Harvey Triana
Private Function IsNumeric(ByVal s As String) As Boolean
    Dim HasDecimal As Boolean = False
    Dim i As Integer = 0
    Dim r As Boolean = False
    Dim ds As Char = Convert.ToChar(DecimalSeparator)
    Dim gs As Char = Convert.ToChar(GroupSeparator)
 
    Do While i < s.Length
        ' Check for decimal
        If s(i) = ds Then
            If HasDecimal Then
                r = False
            Else ' 1st decimal
                ' inform loop decimal found and continue
                HasDecimal = True
                i += 1
                Continue Do
            End If
        End If
        ' check if number
        If Char.IsNumber(s(i)) Or (s(i) = gs) Then
            r = True
        Else
            r = False
            Exit Do
        End If
        i += 1
    Loop
    Return r
End Function
 
Public ReadOnly Property GroupSeparator() As String
    Get
        Return m_GroupSeparator
    End Get
End Property
 
Public ReadOnly Property DecimalSeparator() As String
    Get
        Return m_DecimalSeparator
    End Get
End Property
 
End Class

VB.NET: Clase N2W.vb

 

4. Traducción eficiente desde VB6 hacia VB .NET

El siguiente análisis de la traducción formal desde VB6 hacia VB .NET pone de manifiesto los siguientes detalles importantes que se deberían tener en cuenta para una traducción eficiente:

  1. No emplear el espacio de nombres Microsoft.VisualBasic
    Omitir el espacio de nombres Microsoft.VisualBasic hace bastante más difícil la migración del código, pero establece que vamos a producir un código .NET puro. El espacio de nombres Microsoft.VisualBasic se agrega de manera predeterminada a los proyectos VB .NET; para omitirlo debes entrar a Propiedades, ubicar la ficha Referencias, y desactivar la casilla correspondiente a Microsoft.VisualBasic.

  2. Usar  Option Strict On
    Esto es particularmente importante si deseas producir código muy resistente; evita late bindig que no percibimos. Por otra parte, facilita el camino para migrar el código VB .NET a C#, si se quisiera. Al obligar a usar la conversión formal de tipos, estamos cumpliendo una regla formal de C#. La ausencia de esta directiva tiende a producir un código .NET no puro.

  3. Usar métodos del framework siempre que sea posible
    Al omitir el espacio de nombres Microsoft.VisualBasic, las funciones de cadena clásicas de VB6 como Mid$ , Left$ , y Rigth$ , InStr, y otras, deben ser reemplazadas por los métodos que suministra el framework. En general, SubString reemplaza a Mid$ , Left$ , y Right$, e IndexOf a InStr. No obstante, deben tomarse precauciones ya que SubString por sí solo no produce todo la funcionalidad de estas funciones. Si lo deseáramos, podríamos escribir dichas funciones en un lenguaje .NET para su uso.

  4. Asignación del valor de las variables en su declaración
    VB6 no soporta la asignación del valor de las variables en su declaración. Es conveniente ahorrar líneas de código en VB .NET y escribir las líneas pertinentes.

  5. Reemplazo de arreglos Variant
    La declaración explícita de los arreglos es más intuitiva y elegante en VB .NET; además, podemos usar el tipo pertinente, lo que produce un código de mejor desempeño. Se debe recordar que .NET inicia los arreglos con índice cero; no es adecuado recurrir a artificios .NET para producir arreglos que no inicien en cero pues la potencia de .NET es opacada. Siempre hay forma de reescribir fórmulas que manipulen índices para ajustarse a la norma de .NET.

  6. Usar métodos de operador
    Ya que VB .NET soporta operadores tales como += , &=, conviene usarlos. El desempeño es mejor que usar la sintaxis convencional de VB6.

  7. Usar herencia siempre que sea posible
    Este detalle por sí solo da para un artículo de varias páginas. En realidad, desde una aplicación normal de VB6 es difícil percibir en qué nos beneficiaría la herencia formal. Sin embargo, para aplicaciones grandes, la necesidad se puede vislumbrar con facilidad. Otra cuestión que viene a colación es la herencia que produce Implements de VB6 contra la herencia formal de los lenguajes .NET, o la herencia que produce Implements en los lenguajes .NET. Cuando una aplicación robusta de VB6 ha usado Implements masivamente, es preferible no migrarla a lenguajes .NET. Quizás sea preferible analizar la arquitectura desde un punto de vista .NET y hacer todo de nuevo si el tiempo lo permite. Ese es el caso en algunas de mis aplicaciones.

  8. Operaciones con variables de cadena
    Sabemos que las variables de cadena en .NET son inmutables; es decir, se crea un nuevo espacio de memoria en cada asignación de una variable tipo string. A raíz de ello, el framework suministra la clase StringBuilder para hacer eficientes las operaciones con cadenas. He discutido el asunto con varios expertos en los foros de C# de Microsoft (Jon Skeet, Greg Young e Ignacio Machin, entre otros). La conclusión es que si las operaciones con cadena requieren varios ciclos de computación, típico en un bucle largo, es imperioso usar StringBuilder; si por el contrario las iteraciones son de un número discreto, no muy grande, está permitido el uso directo de String en operaciones de cadena, sin mucha pérdida de desempeño.  En el ejemplo del artículo, las operaciones con cadena rara vez superan las ocho iteraciones, por lo que es eficiente mantener el código si recurrir a StringBuilder.

  9. Una función IsNumeric eficiente
    Los lenguajes .NET en su especificación no incorporan IsNumeric, pero hay varias formas de reproducir la función. El artículo "Which IsNumeric method should you use?", por Ambrose Little, polemiza sobre el asunto y suministra una función con mejor desempeño, que es la que uso en este artículo, traducida desde C# a VB .NET. Recomendable.

Posiblemente se te ocurran otras reglas de traducción VB6 a VB .NET; por mi parte, he descrito las que a mi parecer son el principio.

 

5. Probando la clase CN2W de VB .NET

La clase CN2W puede usarse en cualquier contexto .NET. A continuación vemos un ejemplo extraído de una aplicación de Windows con VB .NET. Con los nombres debería ser suficiente para intuir su uso.

Private Sub btnCurrencyToWords_Click( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles
 btnCurrencyToWords.Click
    Dim n2w As CN2W = New CN2W()
    Me.txtOutput.Text = n2w.CurrencyToWords(Me.txtNumber.Text, "Dolars")
End Sub

Ejemplo de uso de la clase N2W de VB .NET

En la descarga de este artículo encontrarás la aplicación N2W_VB completa.

 

6. Solución en C#

Es posible traducir una aplicación VB6 a C#, pero es mucho más dificil que migrar primero a VB .NET y luego a C#. Los lenguages .NET tienen su asidero en C#, y éste debería ser la opcion para comenzar una aplicación .NET desde cero. Abandoné C en 1995 cuando descubrí Visual Basic; uno hacia las cosas en menos de la tercera parte del tiempo. No obstante, la programacion por punteros se olvida si no se practica; además es horrorosa. Así pues, me casé con Visual Basic. Ahora, VS 2005 nos trae un C que se depura como Visual Basic y el Intellisense es potente ¿Por qué no usarlo? Además, ¡Este maldito C# es muy bonito!

El código del problema expuesto en este artículo en C#, es el siguiente:

using System;
using System.Globalization;
 
public class CN2W
{
    const string ZERO = "Zero";
 
    string IntegerPart = ZERO;
    string RealPart = ZERO;
 
    string _DecimalSeparator;
    string _GroupSeparator;
 
    string[] aT0 = new string[] {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};
    string[] aT1 = new string[] {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen",
 "Seventeen", "Eighteen", "Nineteen"};
    string[] aT2 = new string[] {"Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety" };
    string[] aT3 = new string[] {"", "", " Thousand ", " Million ", " Billion ", "Trillion ", "", "", "", "" };
 
    public CN2W()
    {
        _DecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator;
        _GroupSeparator =  CultureInfo.CurrentCulture.NumberFormat.CurrencyGroupSeparator;
    }
 
    public string IntegerToWords(string Number)
    {
        RealToWords(Number);
        return IntegerPart;
    }
 
    public string RealToWords(string Number)
    {
        int DotPos = 0;
 
        IntegerPart = ZERO;
        RealPart = ZERO;
 
        if (IsNumeric(Number))
        {
            Number = Number.Replace(_GroupSeparator, "");
            DotPos = Number.IndexOf(_DecimalSeparator);
            if (DotPos >= 0)
            {
                IntegerPart = ToWords(Convert.ToInt32(Number.Substring(0, DotPos)));
                RealPart = ToWords(Convert.ToInt32(Number.Substring(DotPos + 1, Number.Length - DotPos - 1)));
            }
            else
            {
                IntegerPart = ToWords(Convert.ToInt32(Number));
            }
        }
        return IntegerPart + " Dot " + RealPart;
    }
 
    public string CurrencyToWords(string Number, string MoneyName)
    {
        string s;
 
        IntegerPart = ZERO;
        RealPart = ZERO;
 
        if(IsNumeric(Number))
        {
            // round to money number
            s = RealToWords(RoundNumberString(Convert.ToDouble(Number), 2));
        }
        // add money text
        if (IntegerPart == ZERO) {IntegerPart = "No";}
        switch(RealPart)
        {
            case ZERO:
                RealPart = "And No Cents";
                break;
            case "One":
                RealPart = "And One Cent";
                break;
            default:
                RealPart = "And " + RealPart + " Cents";
                break;
        }
        return IntegerPart + " " + MoneyName + " " + RealPart;
    }
 
    private string ToWords(int Number)
    {
        string s = "";
        string d = "";
        string r = "";
        int n;
 
        s = Number.ToString();
        n = 1;
        while (s.Length != 0)
        {
            // convert last 3 digits of s to English r.
            if (s.Length < 3) { d = ConvertHundreds(s); }
            else { d = ConvertHundreds(s.Substring(s.Length - 3, 3)); }
            if (d.Length > 0) { r = d + aT3[n] + r; }
            if (s.Length > 3) { s = s.Substring(0, s.Length - 3); }
            else { s = ""; }
            n++;
        }
        if (r.Length == 0) { r = ZERO; }
        return r;
    }
    private string ConvertHundreds(string pNumber)
    {
        string rtn = "";
 
        if (!(Convert.ToInt32(pNumber) == 0))
        {
            // append leading zeros to number
            pNumber = ("000" + pNumber).Substring(pNumber.Length, 3);
            // do we have a hundreds place digit to convert?
            if (!(pNumber.Substring(0, 1) == "0"))
            {
                rtn = ConvertDigit(pNumber.Substring(0, 1)) + " Hundred ";
            }
            // do we have a tens place digit to convert?
            if (pNumber.Length >= 2)
            {
                if (!(pNumber.Substring(1, 1) == "0"))
                {
                    rtn += ConvertTens(pNumber.Substring(1));
                }
                else
                {
                    rtn += ConvertDigit(pNumber.Substring(2));
                }
            }
            return rtn.Trim();
        }
        else { return ""; }
    }
 
    private string ConvertTens(string pTens)
    {
        string r = "";
        // is value between 10 and 19?
        if ((Convert.ToInt32(pTens.Substring(0, 1)) == 1))
        {
            r = aT1[Convert.ToInt32(pTens) - 10];
        }
        else
        {
            // otherwise it's between 20 and 99.
            r = aT2[Convert.ToInt32(pTens.Substring(0, 1)) - 2] + " ";
            // convert ones place digit
            r += ConvertDigit(pTens.Substring((pTens.Length - 1), 1));
        }
        return r;
    }
 
    private string ConvertDigit(string pNumber)
    {
        if (pNumber == "0") { return ""; }
        else { return aT0[Convert.ToInt32(pNumber) - 1]; }
    }
 
    private string RoundNumberString(double Number, int Decimals)
    {
        string s;
        double r;
        // round first
        r = Math.Pow(10d, Decimals);
        // Math.Floor make sure the float round. Suggested by Guillermo Som
        r = (int)(Math.Floor(Number * r + 0.5d)) / r;
        // complete with zeros
        s = r.ToString();
        if ((s.IndexOf(_DecimalSeparator) < 0))
        {
            s += _DecimalSeparator;
        }
        while ((s.Substring(s.IndexOf(_DecimalSeparator)).Length <= Decimals))
        {
            s += "0";
        }
        return s;
    }
 
    // Source: http://aspalliance.com/articleViewer.aspx?aId=80&pId=
    // Review by Harvey Triana
    private bool IsNumeric(string s)
    {
        bool hasDecimal = false;
        bool r = false;
        char ds = Convert.ToChar(_DecimalSeparator);
        char gs = Convert.ToChar(_GroupSeparator);
 
        for (int i = 0; i < s.Length; i++)
        {
            // check for decimal
            if (s[i] == ds)
            {
                if (hasDecimal) // 2nd decimal
                    r = false;
                else // 1st decimal
                {
                    // inform loop decimal found and continue
                    hasDecimal = true;
                    continue;
                }
            }
            // check if number
            if (char.IsNumber(s[i]) || (s[i] == gs))
                r = true;
            else
            {
                r = false;
                break;
            }
        }
        return r;
    }
 
    public string GroupSeparator
    {
        get { return _GroupSeparator; }
    }
    public string DecimalSeparator
    {
        get { return _DecimalSeparator; }
    }
}

Clase N2W en C#

Si comparamos el código VB .NET contra el código C#, no hay mucho para decir. El código C# es como un dibujo calcado del codigo VB .NET puro; o al contrario, si así lo prefieres. C# produce un código horizontal más corto y uno vertical más largo (que es diferente a menor número de líneas de código).

Aunque sí hay un detalle simpático que se puede mencionar: el operador ^ de VB .NET no tiene un equivalente en C#; es por ello que usamos Math.Pow()-supongo que se conservó el operador ^ en VB .NET porque ya sería el colmo del olvido con los emigrantes de VB6.

 

7. Probando la clase CN2W de C#

La clase CN2W puede usarse en cualquier contexto .NET. A continuación vemos un ejemplo extraído de una aplicación de Windows con C#:

private void btnCurrencyToWords_Click(object sender, EventArgs e)
{
    CN2W n2w = new CN2W();
    this.txtOutput.Text = n2w.CurrencyToWords(this.txtNumber.Text, "Dolars");
}

Ejemplo de uso de la clase N2W de C#

En la descarga de este artículo encontrarás la aplicación N2W_VB completa.

 

8. Conclusión

Si vamos a traducir una aplicación VB6 a VB .NET, no deberíamos usar el espacio de nombres Microsoft.VisualBasic. Además, deberíamos pegarnos a Option Strict On, ya que de esta forma se va a producir un código con mejor fidelidad y eficiencia. Escribir VB .NET puro es equivalente a escribir C#; no existe gran diferencia. Cuando escribes VB .NET puro realmente estás usando .NET en su verdadero potencial. VB .NET no es, como algunos piensan, la versión moderna de Microsoft Visual Basic.

Harvey Triana es Ingeniero de Petróleos y se especializa en el desarrollo de software para ingeniería con las tecnologías .net y VB clásico. Ha sido MVP VB y actualmente participa en forma activa en los news públicos de MS.