Reflection II: Llamando a una función de una clase

ForTutorial NET

En este artículo, explicaremos los pasos que tenemos que hacer para llamar a una función de una clase, para que es útil y algún posible inconveniente. Es una continuación de Reflection I: Empezando.

¿Para que es útil?

Es muy útil, como por ejemplo:

    • En soluciones grandes hay varios proyectos y quizá tengas que hacer referencia a una función que esta en un proyecto que hace referencia al tuyo, para ello necesitamos hacerlo mediante reflection. Esto al compilar te puede dar un error de referencia circular, esto es que, al compilar y depender de otro proyecto, lo intenta compilar y este, intenta compilar el primer proyecto… como veréis si no tenéis bien estructurada la aplicación puede ser engorroso.

      Por ejemplo: Tenemos 2 proyectos, uno que es de Personas con una clase clsPersona, y otro de Coches con una clase clsCoches.

      1. Tenemos una función dentro de clsCoches, que lo que hace es devolver los pasajeros, por lo tanto va a buscar a la clase clsPersona los datos y, en el proyecto Coches, necesitamos referenciar el proyecto Personas.
      2. Por otra parte tenemos que una persona tiene un coche asignado, por lo tanto tenemos una función en clsPersonas que necesita ir a clsCoches para obtener la informacion. También necesitaríamos tener una referencia del proyecto Personas al proyecto Coches.

      Esto provocaria que si borramos las dll en algún momento no nos deje compilar. Para compilar el proyecto Coches es necesario compilar el proyecto Personas y viceversa.
      En mi empresa, por ejemplo, tenemos una macro que descarga los proyectos(unload) (si tenéis varios proyectos lo recomiendo) y esta daba errores porque había una referencia circular.

 

    • Como ya hemos visto en el anterior artículo, para poder llamar a un formulario sin saber nada mas que el nombre de la dll y el nombre de la clase.

 

  • Como vamos a ver en este, para poder llamar a una función de la cual sabemos el nombre de la dll, el nombre de la clase y el nombre y parámetros de la función

 

¿Que necesitamos?

Necesitamos tener una solución con 2 proyectos, en uno hacemos un formulario y un botón y otro proyecto lo creamos como librería con una clase. Y, sobretodo, que compilen en la misma ubicación.

El primer proyecto, el del formulario, para mi se llama mdi y el formulario mdiPral.
El segundo proyecto, la librería de clases, para mi se llama Tools y habrá una clase que se llama clsTools.

Vamos a ello

Primero, en la clstools vamos a hacer una función que nos devuelva un String. Vamos a poner un código parecido a esto:

public String devuelveString()
{
return "Hola";
}

En el mdiPral, tenemos que añadir el using System.Reflection, al principio añadimos esta linea de código:

using System.Reflection;

Después editamos el evento de onClick de el botón y tenemos que hacer una referencia al ensamblado, solo necesitamos saber el nombre de la dll. «AppDomain.CurrentDomain.BaseDirectory» es para saber el directorio actual:

Assembly assCadena = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "tools.dll";) ;

Obtenemos el tipo de la clase pasando-le el nombre de la dll sin extensión junto con el nombre de la clase (están separados por un punto):

            Type tipo= assCadena.GetType("tools.clsTools");

Ahora instanciamos un objeto con ese tipo

           Object oInstanciado = Activator.CreateInstance(tipo);

Si queremos enviar algún atributo, tendríamos que crear un array de objetos donde estarán todos los parámetros, o en su defecto dejarlo vació, de momento lo dejaremos vacio.

Object[] arrParam=new Object[0];

Y teniendo todo esto solo nos falta llamar a la función.

 Object oRespuesta = tipo.InvokeMember("devuelveString", BindingFlags.InvokeMethod, null, oInstanciado, arrParam);

De esta manera ya tendríamos la respuesta de «hola» en oRespuesta, como mucho tendríamos que convertir a String el objeto o hacer un oRespuesta.ToString().

Vamos a ver un ejemplo de como pasar varios parametros a una función. En este caso, enviaremos 2 cadenas de texto y un numero.

   Assembly assCadena = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "tools.dll");
            Type tipo = assCadena.GetType("Tools.clsTools");
            Object oInstanciado = Activator.CreateInstance(tipo);

            Object[] arrParam = { "parametro1", "parametro2", 44 };
            Object oRespuesta = tipo.InvokeMember("devuelveString", BindingFlags.InvokeMethod, null, oInstanciado, arrParam);