martes, 23 de noviembre de 2010

Silverlight Tip - Mostrar el Número de versión

Si estás desarrollando una aplicación en Silverlight y quieres mostrar el número de versión de tu aplicación, una vez tengas configurado el fichero AssemblyInfo.vb de tu proyecto, añade el siguiente código:
Dim FullName As String = Assembly.GetExecutingAssembly().FullName
Dim Name As AssemblyName = New AssemblyName(FullName)
Dim Version As System.Version = Name.Version

VersionNumber.Text = String.Format("Mi Programa v{0}.{1}.{2}", 
                                   Version.Major, 
                                   Version.Minor,
                                   Version.Build)

sábado, 13 de febrero de 2010

Silverlight: Convertir un nombre de color predefinido a SolidColorBrush

Si trabajas con Silverlight es posible que necesites utilizar nombre de colores ("Green","Black", "DarkGreen", etc.) para las propiedades relacionadas con colores. Si intentas hacer esto mismo desde código te encontrarás que no hay ninguna función que convierta el String a un objeto del tipo SolidColorBrush.

Googleando un poco he llegado al siguiente post: My Silverlight experiences: Color / SolidColorBrush object from color name in silverlight El código en si no me ha funcionado pero me ha dado la pista para crear la función siguiente:

        Public Function ConvertToSolidColorBrush(ByVal hexacolor As String) As SolidColorBrush

Dim s As String = String.Format("<SolidColorBrush xmlns='http://schemas.microsoft.com/client/2007' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' Color='{0}'></SolidColorBrush>", hexacolor)
Dim brush As SolidColorBrush = CType(Markup.XamlReader.Load(s), SolidColorBrush)
Return brush

End Function

Te será realmente útil si al cargar información de configuración.

martes, 9 de febrero de 2010

¿Cuál es mi IP pública?

El otro día estaba desarrollando un pequeño programa para actualizar un nombre de dominio que tengo en el proveedor de DNS gratuito de  No-IP y necesitaba saber mi IP pública. Buscando encontré que la página What Is My IP ofrece una página ASP que te ofrece esta información así que he creado la siguiente función:


Public Function WhatIsMyIP() As String

Dim WhatIsMyIPUrl As String = "http://whatismyip.com/automation/n09230945.asp"
Dim req As HttpWebRequest
Dim res As HttpWebResponse
Dim Stream As IO.Stream
Dim PublicIP As String = String.Empty
Dim sr As StreamReader

Try
req = WebRequest.Create(WhatIsMyIPUrl)
res = req.GetResponse()
Stream = res.GetResponseStream()
sr = New StreamReader(Stream)
PublicIP = sr.ReadToEnd()
sr.Dispose()
Catch ex As Exception

End Try

Return PublicIP

End Function

viernes, 5 de febrero de 2010

Métodos de extensión para VB.NET

¿Habéis utilizado alguna vez los Métodos de extensión? Es una de las novedades que incorporaba el ya viejo Visual Studio 2008 para VB.NET pero que te permite añadir funcionalidad a clases ya existentes sin necesidad de tener que usar herencia o polimorfismo. Imagínate que necesitas una función que "limpie" un String y sólo deje los números y elimine letras, signos de puntuación, etc. ¡La típica función para extraer números de matrículas y de NIF!
Para implementar dicha funcionalidad normalmente crearíamos una clase que tuviera este método y la iríamos instanciando donde la necesitáramos. Un paso más allá cogeríamos ese método y lo marcaríamos como Shared para tener así un método de clase y evitar así tener que crear la instancia de la clase para llamarlo.
Pues si creamos un método de extensión como este:
   1: Imports System.Runtime.CompilerServices
   2:  
   3: Module Extensions
   4:  
   5:     <Extension()> _
   6:     Public Function ExtraerNumeros(ByVal s As String) As String
   7:         Dim out As String = String.Empty
8: For Each c As Char In s
   9:             If Char.IsNumber(c) Then
10: out = String.Concat(out, c.ToString())
  11:             End If
12: Next
  13:         Return out
14: End Function
  15:  
  16: End Module

Podríamos utilizarlo de la siguiente manera:
1: Dim Numero As String = "98732394-Z".ExtraerNumeros()
Ahora cualquier String que tengáis en vuestra aplicación tendrá ese método como propio.

Nota: Si queréis crear un método de extensión que lo puedan utilizar todas las clases sólo tenéis que pasar como referencia un Object

Haciendo pruebas en Visual Studio 2008 no he conseguido extender un método contra el tipo Object.
Continuará ...

miércoles, 23 de diciembre de 2009

Obtener las clases derivadas de una clase base

Problemática

Tenemos un conjunto de clases que heredan todas de la misma clase base y al iniciar el programa necesitamos inicializar y configurar una instancia de cada una de las clases hijas. Hasta ahora cuando necesitábamos definir una clase hija teníamos que:
1. Crear la nueva clase.
2. Ir al método que inicializa las clases hijas.
3. Ir al método donde se configuran las clases hijas.

¡Un lío! .. y más si tenemos en cuenta que es algo que se hace esporádicamente.

Nuestro deseo era que cuando alguien necesite implementar la definición de una nueva clase hija simplemente deba hacer eso: definirla y punto, del resto de tareas (inicializar y configurar) que se preocupe el programa.

Solución

La solución pasa por usar Reflection. Realizamos una búsqueda en nuestro Assembly de todas las clases existentes que heredan de la clase base y las instanciamos, ¡Así de fácil!

Ejemplo

Primero creamos la clase base y las derivadas:

Public MustInherit Class ClaseBase

Public MustOverride Sub Metodo()

End Class

Public Class ClaseQueHerada
Inherits ClaseBase

Public Sub New()
Console.WriteLine("Constructor de la ClaseQueHerada")
End Sub

Public Overrides Sub Metodo()
Console.WriteLine("ClaseQueHerada.Metodo")
End Sub

End Class

Public Class OtraClaseQueHerada
Inherits ClaseBase

Public Sub New()
Console.WriteLine("Constructor de la OtraClaseQueHerada")
End Sub

Public Overrides Sub Metodo()
Console.WriteLine("OtraClaseQueHerada.Metodo")
End Sub

End Class

En el código siguiente podemos ver como buscamos las clases derivadas, instanciamos y ejecutamos los métodos comunes y todo en tiempo de ejecución.


Module Main

Sub Main()

'Accedemos al Assembly que estamos ejecutando
Dim CurrentAssembly As Assembly = System.Reflection.Assembly.GetExecutingAssembly()
'Con LINQ obtenemos la lista de classes que heredan de ClaseBase, gracias al método IsSubClassOf
Dim q = From t As Type In CurrentAssembly.GetTypes() _
Where t.IsSubclassOf(GetType(ClaseBase))

For Each o As Type In q
'Para cada una de las clases hijas la instaciamos y ejecutamos el método
Console.WriteLine(o.Name)
Dim der As ClaseBase = CurrentAssembly.CreateInstance(o.FullName, True)
der.Metodo()
Next

Console.Read()

End Sub

Con este método de acceso a las clases hijas te puedes ahorrar mucho trabajo.

jueves, 26 de noviembre de 2009

Hasta el infinito y más allá: Visual Studio online

¿Qué pasa cuando 5 tipos muy freaks se encierran para desarrollar?
Eso es lo que hicieron la gente de CodeRun y apareció esto:

coderun

Estos tipos han desarrollado un ¡Visual Studio online! Todo hecho en Javascript y yo que pensaba que lo había visto todo cuando los de Google hicieron Gmail. Si alguien tiene 5 minutos para jugar que le un vistazo al CodeRun Studio.

¿Y para que sirve esto?

Imagínate que estas en un lugar sin portátil y necesitas acceder a tu código fuente, realizar una corrección y compilar. Con esta herramienta “podríamos hacerlo” siempre y cuando no utilicemos sistemas de control de versiones, pruebas unitarias, etc.

La idea está verde aunque se ha realizado ya un trabajo impresionante pero nos da una idea de lo que podremos llevar a ver en la nube.

Toda la aplicación se ha desarrollado con el CodeRun web Toolkit sus propias librerías de controles que tienen a la venta y que no están nada mal.

viernes, 20 de noviembre de 2009

¿Cómo saber el número de registros de una tabla?


Cuando trabajas con SQL Server a veces es necesario consultar cuantos registros tienes en una tabla concreta de la base de datos. Con el script que encontrareis acontinuación obtendreis fácilmente esta infomación.


SELECT
[TableName] = so.name,
[RowCount] = MAX(si.rows)
FROM
sysobjects so,
sysindexes si
WHERE
so.xtype = 'U'
AND
si.id = OBJECT_ID(so.name)
GROUP BY
so.name
ORDER BY
2 DESC

Visto en How do I get a list of SQL Server tables and their row counts?



Si con lo anterior no tienes suficiones el maestro Pinal Dave nos enseña como obtener además el número de columnas y el tamaño en bytes de cada una de las tablas.
El script sería así:


CREATE TABLE #temp (
table_name sysname ,
row_count INT,
reserved_size VARCHAR(50),
data_size VARCHAR(50),
index_size VARCHAR(50),
unused_size VARCHAR(50))
SET NOCOUNT ON
INSERT #temp
EXEC sp_msforeachtable 'sp_spaceused ''?'''
SELECT a.table_name,
a.row_count,
COUNT(*) AS col_count,
a.data_size
FROM #temp a
INNER JOIN information_schema.columns b
ON a.table_name collate database_default
= b.table_name collate database_default
GROUP BY a.table_name, a.row_count, a.data_size
ORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS integer) DESC
DROP TABLE #temp

Visto en SQL SERVER - Query to find number Rows, Columns, ByteSize for each table in the current database - Find Biggest Table in Database

martes, 21 de julio de 2009

Convertir tus objetos en XML directamente

En algunas ocasiones es necesario guardarse un objeto en su estado actual con todas sus propiedades por ejemplo para guardar en un fichero log, o para transferir por algún protocolo que sólo admite texto, etc. En casos como estos suele ser muy práctico utilizar las clases de serialización que vienen nativas en el Framework.net.

Imaginad que tenemos la típica clase Persona que representa un objeto de negocio de nuestra aplicación:

   1:  Public Class Persona
   2:   
   3:      Private _Nombre As String
   4:      Private _Apellidos As String
   5:   
   6:      Public Property Nombre() As String
   7:          Get
   8:              Return _Nombre
   9:          End Get
  10:          Set(ByVal value As String)
  11:              _Nombre = value
  12:          End Set
  13:      End Property
  14:   
  15:      Public Property Apellidos() As String
  16:          Get
  17:              Return _Apellidos
  18:          End Get
  19:          Set(ByVal value As String)
  20:              _Apellidos = value
  21:          End Set
  22:      End Property
  23:   
  24:      Sub New()
  25:          Me.Nombre = String.Empty
  26:          Me.Apellidos = String.Empty
  27:      End Sub
  28:   
  29:  End Class

Para pasar un objeto de esta clase a String necesitamos utilizar las clases System.Xml.Serialization.XmlSerializer y System.IO.StringWriter de la siguiente forma:

   1:  Dim PersonaSerializada As String
   2:  Dim Yo As New Persona()
   3:  Yo.Nombre = "Yo"
   4:  Yo.Apellidos = "Mismo"
   5:   
   6:  Using sw As New StringWriter()
   7:      Dim serialitzador As New XmlSerializer(GetType(Persona))
   8:      serialitzador.Serialize(sw, Yo)
   9:      PersonaSerializada = sw.ToString()
  10:  End Using

Y el resultado que tendríamos sería:

<?xml version="1.0" encoding="utf-16"?>
<Persona xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Nombre>Yo</Nombre>
<Apellidos>Mismo</Apellidos>
</Persona>

Este es un método práctico y rápido para guardar el estado de un objeto en un momento concreto y puede ser muy útil tanto para poder realizar trazas de un procedimiento concreto o para montar un sistema de gestión de excepciones avanzado .. imaginad que cada vez que se produce una excepción tratando un objeto de negocio nos guardamos la información de la excepción y además el objeto entero.

A tener en cuenta:

  • El objeto System.Xml.Serialization.XmlSerializer también incluye el método Deserialize para cargar el objeto de negocio a partir de un String.
  • Si cambiamos las referencias al objeto System.IO.StringWriter por un System.IO.StreamWriter podemos guardar el objeto serializado en un fichero XML directamente.
  • Los procesos de serialización suelen tener un coste elevado para el sistema así que es conveniente utilizarlo en entornos donde no prime el rendimiento de la aplicación … ¿existe hoy día algún sitio donde no sea imprescindible el rendimiento? .. :-P

lunes, 20 de julio de 2009

Asociar descripción a una Enum

Las Enum nos ofrecen la posibilidad de asociar un nombre descriptivo a un conjunto de valores relacionados entre si, estos valores son numéricos.

Public Enum EstadoCivil 
Soltero
Casado
End Enum

Muchas veces cuando tenemos una Enum tenemos la necesidad de obtener el nombre que le hemos dado a uno de los valores como si fuera un String (pe. “Soltero”) para mostrarlo en un mensaje por pantalla o registrarlo en algún fichero, etc.

Acceso directo al valor

Si queremos acceder directamente al literal que le hemos asociado al valor simplemente debemos utilizar el método ToString() del valor:

EstadoCivil.Soltero.ToString("G")

Esta línea de código nos devolvería el String “Soltero”.

Acceder a la descripción detalla del valor

Si lo que queremos es poder acceder a una información mucho más detallada, deberemos tirar de Reflection. Para empezar deberíamos ampliar la definición de la Enum.

Public Enum EstadoCivil
<Description("Un soltero")> Soltero
<Description("Un casado")> Casado
End Enum

Y la forma de acceder sería la siguiente:

Public Function ObtenerDescripcionEstadoCivil(ByVal estado As EstadoCivil) As String

Dim InformacionEstado As FieldInfo = GetType(EstadoCivil).GetField(estado.ToString("G"))
Dim Descripcion As DescriptionAttribute = InformacionEstado.GetCustomAttributes(GetType(DescriptionAttribute), False)(0)

Return Descripcion.Description

End Function

La llamada a esta función nos daría acceso a la descripción que le hemos asignado.

Etiquetas de Technorati: ,,

sábado, 18 de julio de 2009

Inicialización rápida de objetos

Todos sabemos que las instancias de una clase son iniciadas a través de un constructor y que el constructor es un método de la clase que puede ser sobrecargado. Hasta ahí todo correcto, lo de toda la vida.

Constructores “on fly”

La versión actual de VB.NET nos permite iniciar las propiedades públicas de una clase en el momento de la instanciación, en la misma línea de código. Imaginaros la siguiente clase:



Public Class Persona

Private _Nombre As String
Private _Apellidos As String

Public Property Nombre() As String
Get
Return _Nombre
End Get
Set(ByVal value As String)
_Nombre = value
End Set
End Property

Public Property Apellidos() As String
Get
Return _Apellidos
End Get
Set(ByVal value As String)
_Apellidos = value
End Set
End Property

Sub New()
Me.Nombre = String.Empty
Me.Apellidos = String.Empty
End Sub

End Class

La manera natural de iniciar un objeto de esta clase sería:


Dim NuevaPersona As New Persona()
NuevaPersona.Nombre = "Bill"
NuevaPersona.Apellidos = "Gates


Si quisiéramos poder crear una persona directamente con su Nombre y Apellidos deberíamos sobrecargar el constructor por defecto para que aceptara estos dos nuevos parámetros.


Con la versión actual de VB.NET y sin tener que implementar el nuevo constructor podemos hacer:



Dim BillGates As New Persona() With {.Nombre = "Bill", .Apellidos = "Gates"}


¡Este código es equivalente al del ejemplo de antes pero en una sola línea de código! Y si quisiéramos podríamos ir instanciando diferentes objetos con diferentes propiedades configuradas inicialmente:



Dim Bill As New Persona() With {.Nombre = "Bill"}
Dim BillGates As New Persona() With {.Nombre = "Bill", .Apellidos = "Gates"}



Fácil, ¿no?

jueves, 25 de junio de 2009

Detectar si la aplicación web está en modo Debug

Vía: Detecting ASP.NET Debug mode

No os pasa que cuando estais depurando una aplicación web teneís que introducir siempre los mismo parámetro, pasar los mismo procesos de inicialización, etc.

También es muy útil para generar algunos resultado intermedios que utilizas para ver el estado de la aplicación mientras debugas .. saltarte una pantalla de login, etc.

Si eres de los que no soporta hacer mil veces estas tareas aquí tiene la condición mágica:

If HttpContext.Current.IsDebuggingEnabled Then
'Tareas a realizar
End If

lunes, 2 de marzo de 2009

Ejecución de funciones de modo asíncrono


¿Tienes en tu programa una función que tarda muchísimo en ejecutarse y no tienes que hacer nada con el resultado de esta? Por ejemplo en servicios de notificaciones a los que no esperas que te confirmen su recepción, escribir en un fichero de Log, insertar en un registro en una tabla, etc. En general acciones que no tienen que ver con la funcionalidad principal que estamos ejecutando en ese momento.
Si te has encontrado en esta situación .. ¡el esperar se va a acabar! Tenemos los Delegate.
Los delegados son básicamente un puntero a un función de tu programa, ¡Tranquilos! No vamos a ver nada de punteros .. no estamos en C. Lo que hace el .NET Framework es ejecutar tu función en otro subproceso de tu aplicación, sin tener que crear Thread.

Por ejemplo, imaginad que tenemos la siguiente función de nuestro programa:


Private Sub FuncionEjecutadaAsincrona(ByVal parametro1 As String)
'Código pesado del cual no esperamos su respuesta
End Sub

Para crear su delegado simplemente tendríamos que definir la así:
Private Delegate Sub FuncionEjecutadaAsincronaDelegate(ByVal parametro1 As String)

Efectivamente como podéis ver simplemente tenéis que utilizar la misma definición del procedimiento añadiendo la palabra Delegate.
Ahora sólo falta llamar a nuestra función que se hará así:

Dim deleg As FuncionEjecutadaAsincronaDelegate
deleg = New FuncionEjecutadaAsincronaDelegate(AddressOf FuncionEjecutadaAsincrona)
deleg.BeginInvoke("Parametro1", Nothing, Nothing)

¡Y ya está! Al realizar la llamada a BeginInvoke se lanza nuestra función. Los dos parámetros a Nothing permiten, si es una función, recibir la información de respuesta pero eso lo veremos otro día.

sábado, 17 de enero de 2009

El patrón de diseño Singleton

El patrón de diseño Singleton, o de Instancia única, nos permite asegurar que de una determinada clase sólo hay un instancia en todo el sistema.

La idea es que nuestra clase Singleton no mostrará públicamente las operaciones necesarias para su instanciación (constructor) y por lo tanto será ella quien misma quien gestiones su instanciación.

Imaginaros la típica clase de acceso a la base de datos o a unos datos de configuración o a un sistema de escribir un fichero LOG. Realmente son tareas que realizamos en todos nuestros programas y seguramente lo resolvemos guardando información en variables globales o realizando el proceso de carga o configuración cada vez que lo necesitamos.
En todos estos casos es muy interesante tener la posibilidad de tener una clase común que nos proporcione acceso a sus recursos pero sin tener que estar instanciando la clase cada vez que la necesitamos.

La implementación de patrón Singleton en VB.NET sería así:

Public NotInheritable Class Singleton

Private Shared _Instance As Singleton = Nothing
Private Shared ReadOnly _Sync As New Object

Private Sub New()
End Sub

Public Shared ReadOnly Property Instance() As Singleton
Get
If _Instance Is Nothing Then
SyncLock _Sync
If _Instance Is Nothing Then
_Instance = New Singleton()
End If
End SyncLock
End If
Return _Instance
End Get
End Property

End Class


Para utilizar la clase que hemos creado simplemente hay que definir una variable de ese objeto y llamar a la propiedad Instance.


Dim MiSingleton As Singleton = Singleton.Instance
'Ejemplo de llamada de un Metodo de Singleton
MiSingleton.HacerAlgo()



Aquí os dejo el fichero Singleton.vsi que os permitirá incluir en vuestro Visual Studio el code snippet del patrón Singleton.

martes, 13 de enero de 2009

Gestión global de excepciones

Software bug 04

Aunque cada vez el software que desarrollamos es más robusto la verdad es que nadie se escapa de dejar algún gazapo que en cualquier momento se le presentará al usuario final en forma de un horrible mensaje de error.

Si queremos evitar estas situaciones podemos definir los eventos UnhandledException y ThreadException en nuestros programa y problema resuelto. La verdad es que no parece demasiado lógico que tengamos que definir dos eventos para capturar las excepciones que no controlamos pero el primero se encarga de manejar las que no tienen que ver con el interface gráfico y el segundo se encarga de las visuales.

La implementación sería de la siguiente manera:

  1. Definición de los eventos:
    Private Sub Form1_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load

    Dim currentDomain As AppDomain = AppDomain.CurrentDomain
    AddHandler currentDomain.UnhandledException, AddressOf AppDomain_UnhandledException
    AddHandler Application.ThreadException, AddressOf Application_ThreadException

    End Sub


  2. Declaración del evento que maneja la UnhandledException:

    Private Sub AppDomain_UnhandledException(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)

    Dim st As New StackTrace()
    Dim pila As String = st.ToString() 'Obtenemos el estado actual de la pila

    Dim ex As Exception = DirectCast(e.ExceptionObject, Exception)

    'Acciones a realizar para registrar las excepciones
    MessageBox.Show("UnhandledException" & ex.Message)

    End Sub


  3. Declaración del evento que maneja la ThreadException:

    Private Sub Application_ThreadException(ByVal sender As Object, ByVal e As Threading.ThreadExceptionEventArgs)

    Dim st As New StackTrace()
    Dim pila As String = st.ToString()

    'Acciones a realizar para registrar las excepciones
    MessageBox.Show("ThreadException" & e.Exception.Message & ". " & pila)

    End Sub


¡Y eso es todo! Ahora ya no hay excusa para no facilitarle el trabajo al usuario final mostrándole esos feos mensajes de error y además nos permitirá registrar toda la información existente en el sistema en el momento que se lanzó la excepción.

domingo, 7 de diciembre de 2008

La función Replace de Microsoft.VisualBasic

Etiquetas de Technorati: ,

Muchos de los que ahora programamos en VB.NET venimos del viejo mundo del VB6, ese mundo de caos donde no existía la orientación a objetos y para muchas cosas tenias que tirar de la API de Windows.

Ahora que utilizamos VB.NET nuestro mundo se ha simplificado mucho pero tenemos que ir con cuidado ¡sin darnos cuenta vamos y volvemos al lado oscuro! Ya que dentro del framework existe la librería Microsoft.VisualBasic.dll que es un vínculo que nos han dejado los desarrolladores de Microsoft para que la transición fuera menos traumática.
El problema es que ese vínculo que nos dejaron con el pasado afecta directamente contra el rendimiento de nuestras aplicaciones. Un ejemplo claro de sería la función Replace.


Dim str As String = "ABA"
str = Replace(str, "A", "X")


Cuando utilizamos la función Replace, estamos llamando la función que hay en la librería Microsoft.VisualBasic, denominada Strings.Replace.









Si decompilamos esta función, con .NET Reflector, vemos que realmente se llama a la siguiente función:

















   1: Public Shared Function Replace(ByVal Expression As String, ByVal Find As String, ByVal Replacement As String, ByVal Optional Start As Integer = 1, ByVal Optional Count As Integer = -1, <OptionCompare> ByVal Optional [Compare] As CompareMethod = 0) As String








   2:     Dim str As String








   3:     Try 








   4:         If (Count < -1) Then








   5:             Throw New ArgumentException(Utils.GetResourceString("Argument_GEMinusOne1", New String() { "Count" }))








   6:         End If








   7:         If (Start <= 0) Then








   8:             Throw New ArgumentException(Utils.GetResourceString("Argument_GTZero1", New String() { "Start" }))








   9:         End If








  10:         If ((Expression Is Nothing) OrElse (Start > Expression.Length)) Then








  11:             Return Nothing








  12:         End If








  13:         If (Start <> 1) Then








  14:             Expression = Expression.Substring((Start - 1))








  15:         End If








  16:         If (Find Is Nothing) Then








  17:             Return Expression








  18:         End If








  19:         If ((Find.Length = 0) OrElse (Count = 0)) Then








  20:             Return Expression








  21:         End If








  22:         If (Count = -1) Then








  23:             Count = Expression.Length








  24:         End If








  25:         str = Strings.ReplaceInternal(Expression, Find, Replacement, Count, [Compare])








  26:     Catch exception As Exception








  27:         Throw exception








  28:     End Try








  29:     Return str








  30: End Function














Esta a su vez llama a :

















   1: Private Shared Function ReplaceInternal(ByVal Expression As String, ByVal Find As String, ByVal Replacement As String, ByVal Count As Integer, ByVal [Compare] As CompareMethod) As String








   2:     Dim ordinal As CompareOptions








   3:     Dim compareInfo As CompareInfo








   4:     Dim num5 As Integer








   5:     Dim length As Integer = Expression.Length








   6:     Dim num2 As Integer = Find.Length








   7:     Dim builder As New StringBuilder(length)








   8:     If ([Compare] = CompareMethod.Text) Then








   9:         compareInfo = Utils.GetCultureInfo.CompareInfo








  10:         ordinal = (CompareOptions.IgnoreWidth Or (CompareOptions.IgnoreKanaType Or CompareOptions.IgnoreCase))








  11:     Else








  12:         compareInfo = Strings.m_InvariantCompareInfo








  13:         ordinal = CompareOptions.Ordinal








  14:     End If








  15:     Do While (num5 < length)








  16:         Dim num4 As Integer








  17:         If (num4 = Count) Then








  18:             builder.Append(Expression.Substring(num5))








  19:             Exit Do








  20:         End If








  21:         Dim num3 As Integer = compareInfo.IndexOf(Expression, Find, num5, ordinal)








  22:         If (num3 < 0) Then








  23:             builder.Append(Expression.Substring(num5))








  24:             Exit Do








  25:         End If








  26:         builder.Append(Expression.Substring(num5, (num3 - num5)))








  27:         builder.Append(Replacement)








  28:         num4 += 1








  29:         num5 = (num3 + num2)








  30:     Loop








  31:     Return builder.ToString








  32: End Function














Conclusión:








Cuando hacemos un Replace realmente estamos creando un StringBuilder y ejecutando un bucle While. Increible, ¿no?









Solución:








Normalmente cuando utilizamos esta función es para realizar un reemplazo de todas la coincidencia y no utilizamos la mayoría de opciones de ofrece la función Replace. Yo me simplifico la vida y utilizo la que viene nativa con el tipo String.

















   1: Dim str As String = "ABA"








   2: str = str.Replace("A", "X")














That's it!

domingo, 30 de noviembre de 2008

Las reglas de la optimización son sencillas. Regla 1: No optimices. Regla 2 (solo para expertos): No optimices todavía.

Cuantas veces estamos delante de un programa, creando una función y de repente nos desviamos de nuestro objetivo principal para emprender una cruzada para reducir el tiempo de procesamiento e intentar lograr que esa función o procedimiento se ejecuto lo más rápido posible.
Seguramente esta situación nos la encontramos más veces de las que deseamos.

Este proceso se denomina optimización prematura y se produce cuando el programador permite que las consideracionesStop ! Right now !s de reducción del tiempo o espacio afectan al diseño inicial.

Normalmente las decisiones de optimización en la etapa de codificación son subjetivas, básicamente se basan en las sensaciones que el programador tiene durante esta fase y no en datos empíricos.

Antes de iniciar un proceso de optimización del código fuente os recomiendo:

  1. Asegurarse que sigue el diseño preestablecido en las etapas anteriores.
  2. Crear una batería de pruebas que nos permita confirmar que cumple todas las funcionalidades acordadas en el análisis funcional.
  3. No optimices.

Las optimizaciones de código se deben hacer siempre después de que este se haya finalizado y probado correctamente certificando así que cumple las especificaciones funcionales establecidas en las etapas previas.
Es preferible no optimizar hasta que realmente lo necesitemos, en ese momento se deberá estudiar dónde y cómo optimizar ya que no todo depende de nuestro código fuente y pueden existir recursos externos se deban tener en cuenta.