REFLECTION: Invocar un método a partir de un String…

En esta segunda entrega les voy a mostrar como hacer para invocar un método, a partir de una cadena de String, la cual contiene simplemente el nombre del método.

Si inspeccionamos un poco la clase Type del framework podemos ver que tiene un método llamado Type.GetMethod(), el cual obtiene información de un método.
Lo que necesitamos saber de este método es que recibe como párametros el nombre del método y opcionalmente un Array con los tipos de los parámetros (para el caso de que exista sobrecargas de método), siendo que nos devuelve el MethodInfo relacionado.
Este MethodInfo tiene una gran cantidad de miembros, entre los cuales, los que se destacan son:

  • GetParameters(): obtiene los parámetros del método o constructor especificado.
  • GetType(): obtiene el objeto Type de la instancia actual.
  • Invoke(): realiza la llamada al método.
  • Attributes: obtiene los atributos asociados a este método.
  • IsConstructor.
  • IsAbstract, IsPrivate, IsPublic, IsStatic, IsVirtual.
  • ReturnType: obtiene el tipo de valor devuelto por este método.
  • Otros.

Lo que necesitamos utilizar entonces es el método Invoke(). La firma más común de este método es la Invoke(Object obj, Object[] parameters), donde:

  • obj: objeto en el que debe invocarse el miembro o constructor. Si el método o constructor es de clase o estático, se pasa null. Si, en cambio es un método o constructor de instancia, se debe pasar el objeto en el cual queremos ejecutar ese método.
  • parameters: lista de argumentos del método o constructor invocado. Este array debe tener el mismo número, orden y tipo que los parámetros del método o constructor que se va a invocar. Si no hay ningún parámetro, parameters debe ser null.

Les muestro un ejemplo, en el cual realizo una llamada a un método de clase o estático:

//obtengo el tipo
Type tipo = Type.GetType(namespaceTipo);

//obtengo la información del método, sé que no tiene sobrecargas
MethodInfo metodo = tipo.GetMethod(nombreMetodoEstatico);

DataSet ds = new DataSet();

//objeto que devuelve el método de clase
object objVuelta;

//tiene parámetros y sé que es un objeto de tipo DataSet 
objVuelta = metodo.Invoke(null, new object[] { ds }); 

otro ejemplo, pero con llamada a método de instancia:

//tengo una instancia
MiClase miInstancia = new MiClase();

//obtengo el tipo
Type tipo = miInstancia.GetType();

//Array de tipos
Type[] tiposParametros = new Type[] { typeof(Int32) };

//obtengo la información del método de instancia de la clase MiClase, sobrecarga de Int32
MethodInfo metodo = tipo.GetMethod(nombreMetodoInstancia, tiposParametros);

Int32 parametro = 3;

//invoco el método, con parámetro igual a 3
Object objVuelta = metodo.Invoke(miInstancia, new object[] { parametro }); 

REFLECTION: Crear una instancia a partir de un String con el nombre de la clase…

Hay muchas situaciones en las que se nos hace necesario crear una instancia de una clase a partir de una cadena de caracteres que tenemos almacenada, ya sea para utilizarla en una Factory o para mantener cierta abstracción en el tipo de datos que se maneja.
Cualquiera sea el caso, deberíamos tener un String con formato “assembly-qualified name”.
Comunmente se utiliza el siguiente formato:
“namespace+NombreClase, assembly”
(Es importante aclarar que la utilización de este String va a ser case-sensitive).

Ejemplos de assembly-qualified names:

  • “System.Int32”
  • “Configuracion.General.ClaseGeneral, Configuracion.General”
  • “TopNamespace.SubNameSpace.ClaseContenedora+ClaseAnidada, MiAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089”

Lo primero que debemos hacer es obtener el tipo a partir de la cadena de caracteres:

Type tipo = Type.GetType(namespaceControlador);

Una vez que tenemos el tipo, debemos obtener el constructor e invocarlo (en el siguiente ejemplo el constructor que se usa es el vacío):

IControlador controlador = (IControlador)tipo.GetConstructor(Type.EmptyTypes).Invoke(null);

Notar que es necesario tener una interface definida para ese tipo de datos o una clase abstracta de la cual herede, de lo contrario se nos haría casi imposible manejarlo (digo casi porque también podemos ejecutar un método a partir de un String).

GetConstructor(Type.EmptyTypes): obtiene el constructor a partir de los tipos de los parámetros que el mismo acepta. En este caso obtenemos el constructor que no tiene parámetros, en otros casos deberíamos pasarle un array con los tipos.
Invoke(null): invocamos el método (en este caso el constructor) pasandole los parámetros como un array, si le pasamos null es que ejecutamos el método sin parámetros.

¿Donde lo podemos utilizar?
En el proyecto en que trabajo necesitaba mantener cierta abstracción en cuanto a los controladores para los distintos tipos de tiqueteras fiscales y no fiscales. Entonces, lo que hice es crear una Factory la cual cuando se le especifica un tipo de tiquetera, va a un almacén de datos (Base de Datos o xml) en busca de un String con el nombre del controlador específico. Una vez teniendo ese String, creo el controlador usando reflection y lo uso… Así logro que el día de mañana si se agrega un nuevo tipo de tiquetera o un nuevo controlador, lo único que debo hacer es redefinir el String del controlador.

Enumeraciones + manipulación de bits = FLAGS…

Primero, lo primero… qué son las enumeraciones?
Una enumeración (enum) es una forma especial de tipo de valor, que deriva de System.Enum y proporciona nombres alternos para los valores de un tipo primitivo subyacente. Un tipo de enumeración tiene un nombre, un tipo subyacente y un conjunto de campos. (corrección)

Ejemplo:

public enum MessageBoxButtons {
    OK,
    OKCancel,
    AbortRetryIgnore,
    YesNoCancel,
    YesNo,
    RetryCancel
}

MessageBoxButtons boton = MessageBoxButtons.YesNo;

if (boton == MessageBoxButtons.YesNo) {
    //comportamiento propio de YesNo
}
else if (boton == MessageBoxButtons.YesNoCancel) {
    //comportamiento propio de YesNoCancel
}

En el ejemplo muestro la enumeración de MessageBoxButtons, que se utiliza en MessageBox, esta enumeración hace que cada cadena toma un valor (en este caso implícito) empezando por 0. Cada uno de los valores tiene un funcionamiento individual.

Si lo que necesitamos es permitir ingresar combinaciones de valores de la enumeración, lo que debemos usar es una enumeración del tipo Flags.
Las enumeraciones Flags se basan en la utilización de operaciones entre bits de sus valores. En las operaciones de manipulación de bits se utilizan muy frecuentemente los operadores & (AND), | (OR), ^ (XOR) y ~ (NOT). Si no saben como utilizar estos operadores, en este link pueden encontrar una guía en inglés muy interesante.
De antemano les puedo ir diciendo que las combinaciones se hacen (para estos casos) con el operador | y la evaluación de las condiciones con &.

La declaración de una enumeración Flags se hace de la siguiente manera:

[Flags]
public enum NombreEnumeracion {
    Cadena0 = 0, //opcional
    Cadena1 = 1,
    Cadena2 = 2,
    Cadena3 = 4,
    Cadena4 = 8,
    //...
}

Los valores que toman las cadenas son potencias enteras de 2, de ahí el tratamiento de bits.
Nada mejor que un ejemplo para comprender como utlizarlo:

[Flags]
public enum TipoLimpieza {
   Ninguna = 0,
   Cliente = 1,
   Servicio = 2,
   Todo = Cliente | Servicio
}

esta enumeración la utilicé en una tarea que tuve en la cual debía limpiar el caché de datos en el cliente, en el servidor, o en ambos…
Acá va la implementación:

TipoLimpieza tipo = (TipoLimpieza)objetoTipoLimpieza;

if (tipo == TipoLimpieza.Cliente) {
    //1. limpieza SOLO en cliente
}
if ((tipo & TipoLimpieza.Cliente) == TipoLimpieza.Cliente) {
   //2. limpieza en cliente, ya sea Cliente sólo o Cliente y Servicio
}
if ((tipo & TipoLimpieza.Servicio) == TipoLimpieza.Servicio) {
   //3. limpieza en servicio, ya sea servicio sólo o Servicio y Cliente
}
//notar que por la enumeración 0 (Ninguno) no se hace nada

entonces, al utilizarlo con los distintos valores:

//cuando:
tipo = TipoLimpieza.Ninguna;
//no se realiza nunguna operación.

//cuando:
tipo = TipoLimpieza.Cliente;
//se ejecuta el código de las condiciones: 1 y 2.

//cuando:
tipo = TipoLimpieza.Servicio;
//se ejecuta el código de la condición: 3.

//cuando:
tipo = TipoLimpieza.Cliente | TipoLimpieza.Servicio;
//se ejecuta el código de la condición: 2 y 3.
Publicado en C#. Etiquetas: . Leave a Comment »

Como implementar correctamente IDisposable…

Primero lo primero… La interface IDisposable define un método “personalizado” para liberar los recursos administrados y no administrados.
IDisposable se usa principalmente para liberar los recursos no administrados, ya que el recolector de elementos no utilizados (GC: Garbage Collector) libera automáticamente la memoria asignada a un objeto administrado cuando ya no se utiliza, pero no se puede prever cuándo se producirá la recolección de elementos no utilizados. Además, el GC no reconoce recursos no administrados, como ser objetos de tipos File y Font.

A continuación, les muestro el código de ejemplo y aclaraciones sobre la implementación de una clase IDisposable:

public class ClaseDisposable : IDisposable {
    // Recursos manejados
    private Component componentes = new Component();
    private DataSet dataSetDisposable = new DataSet();

    // Indica si ya se llamo al método Dispose. (default = false)
    private Boolean disposed;

    /// <summary>
    /// Implementación de IDisposable. No se sobreescribe.
    /// </summary>
    public void Dispose() {
        this.Dispose(true);
        // GC.SupressFinalize quita de la cola de finalización al objeto.
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Limpia los recursos manejados y no manejados.
    /// </summary>
    /// <param name="disposing">
    /// Si es true, el método es llamado directamente o indirectamente
    /// desde el código del usuario.
    /// Si es false, el método es llamado por el finalizador
    /// y sólo los recursos no manejados son finalizados.
    /// </param>
    protected virtual void Dispose(bool disposing) {
        // Preguntamos si Dispose ya fue llamado.
        if (!this.disposed) {
            if (disposing) {
                // Llamamos al Dispose de todos los RECURSOS MANEJADOS.
                this.componentes.Dispose();
                this.dataSetDisposable.Dispose();
            }

            // Acá finalizamos correctamente los RECURSOS NO MANEJADOS
            // ...

        }
        this.disposed = true;
    }

    /// <summary>
    /// Destructor de la instancia
    /// </summary>
    ~ClaseDisposable() {
        this.Dispose(false);
    }
}

Podemos agregar que el método Dispose(bool disposing) es virtual, por lo que podemos redefinirlo en clases que hereden de esta, por lo cual en dichas clases no necesitamos implementar nuevamente IDisposable. Un ejemplo de este comportamiento es un Formulario que hereda (obviamente) de Form, como vemos a continuación, en Designer tenemos el siguiente código:

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
     if (disposing && (components != null)) {
          components.Dispose();
     }
     base.Dispose(disposing);
}

También podemos ver como sería la llamada a Dispose. Hay dos tipos de llamadas, la directa y la indirecta:
Llamada Directa:

ClaseDisposable objetoDisposable = new ClaseDisposable();
// utilizamos el objetoDisposable
// ...
// y lo finalizamos:
objetoDisposable.Dispose();

Llamada Indirecta:

using (ClaseDisposable objetoDisposable = new ClaseDisposable()) {
    // utilizamos el objetoDisposable
    // ...
}
//se finaliza automáticamente al salir del using

Más información sobre using…

Espero que les sea útil.
(FxCop nos sugiere la implementación de IDisposable de esta manera cuando nuestra clase trabaja con recursos administrados y que implementan el método Dispose… Es bueno hacerle caso, implementando IDisposable como corresponde 😀 )

Publicado en C#, Tips. Etiquetas: . Leave a Comment »

StringBuilder…

Ante la necesidad de manipular cadenas de caracteres dinámicamente nos encontramos con dos posibilidades:

  1. manejar cadenas con la clase String y realizar sobre él acciones como ser concatenación, reemplazo, inserción, etc.
  2. manejar cadenas con la clase StringBuilder.

Lo más común y más “fácil” es trabajar con String, mantener una instancia e ir realizando tratamientos sobre ella, como ser concatenar strings por medio del operador +,  lo cual nos lleva a crear código poco performante y hasta por momentos engorrosos. Dado que los Strings son de tamaño fijo, al concatenar dos cadenas con el operador + se crea una instancia aparte, lo que  lleva a disminuir el rendimiento debido al mal uso de memoria.

Por lo tanto para operar con cadenas de caracteres lo más formal (y también más óptimo) es utilizar la clase StringBuilder.

¿Qué podemos hacer con  StringBuilder?

La clase StringBuilder nos provee los siguientes métodos:

  • Append: Anexa al final de la instancia la representación en forma de cadena de un objeto especificado.
  • AppendFormat: Anexa a la instancia una cadena con formato, que contiene cero o más especificaciones de formato. Cada especificación de formato se reemplaza por la representación en forma de cadena de un argumento de objeto correspondiente.
  • AppendLine: Anexa el terminador de línea predeterminado, o una copia de una cadena especificada y el terminador de línea predeterminado, al final de esta instancia.
  • CopyTo: Copia los caracteres de un segmento especificado de esta instancia al segmento especificado de una matriz Char de destino.
  • EnsureCapacity: Garantiza que la capacidad de la instancia de StringBuilder corresponde como mínimo al valor especificado.
  • Remove: Elimina de la instancia el intervalo de caracteres especificado.
  • Replace: Reemplaza todas las apariciones de un carácter o cadena en la instancia por otro carácter o cadena especificados.
  • ToString: Sobrecargado. Reemplazado. Convierte el valor de un objeto StringBuilder en un objeto String.

Ejemplo:

usando String:

String mensaje = "Medios de pago excedidos de saldo: ";
foreach (DocSaldo.SaldoRow fila in doc.Saldo.Rows) {
    mensaje += Environment.NewLine + fila.MedioPago;
}

usando String Builder:

StringBuilder mensaje = new StringBuilder("Medios de pago excedidos de saldo:");
mensaje.Append(Environment.NewLine);

foreach (DocSaldo.SaldoRow fila in doc.Saldo.Rows) {
    mensaje.AppendLine(fila.MedioPago);
}
String mensajeString = mensaje.ToString();

Como se puede notar, la segunda opción es más formal y me atrevo a decir “más Orientada a Objetos”.

Una observación adicional es el constructor del StringBuilder, el cual en una de sus sobrecargas nos permite inicializarlo con una cadena de caracteres.

Cuando implementamos la primera opción FxCop nos indica con un issue que debemos cambiarlo por el uso de StringBuilder, que es la segunda opción.

Más información:

http://msdn.microsoft.com/es-es/library/system.text.stringbuilder(VS.80).aspx

Publicado en C#, Tips. Etiquetas: . 2 Comments »