Cargar un tipo dinamicamente

dynamictypeproject

  Una aplicación modular suele ser una aplicación donde sus funcionalidades son opcionales, de forma que podemos quitar ó añadirlas según nos convenga. La aplicación solo sabe que va a tratar con instancias que cumplen un determinado contrato, ya sea cumpliendo con una interfaz ó determinado tipo base (usando clases abstractas). Estos contratos suelen estar en ensamblados que conocen las dos partes, de forma que la aplicación espera una instancia de clase que cumple el contrato definido en el ensamblado común, y el ensamblado «opcional» provee una instancia de clase que cumple dicho contrato, dicho contrato ó acuerdo mutuo indica a la aplicación como usar dicha instancia. En el ejemplo de solución de Visual Studio que se ve a la izquierda, LoadTypeTest sería la aplicación, Common el ensamblado compartido donde se definen los contratos y los tipos comunes, y LibraryTest donde se encuentra definida la clase, LoadTypeTest y LibraryTest tienen referenciado a Common, pero se desconocen entre ellos.

En en ensamblado común he definido una interfaz y un delegado, que definen la forma en que la instancia «desconocida» se va a relacionar con la aplicación:

public delegate void DataArrival_(String Data);
 
public interface ITestInterface
{
    String Name { get; }
 
    event DataArrival_ DataArrival;
 
    void SendData(String Data);
}

Si la clase que que implementamos cumpliendo esta interfaz, tiene un constructor por defecto, tenemos dos formas de cargar el tipo dinámicamente:

Reflection:

Assembly myAssembly = Assembly.LoadFrom("LibraryTest.dll");
ITestInterface test2 = myAssembly.CreateInstance("LibraryTest.LibraryTest") as ITestInterface;
test2.DataArrival += new DataArrival_(delegate(String Data)
{
    Console.WriteLine("Received: " + Data);
});
test2.SendData("Hello " + test2.Name + "!!");

Remoting:

ObjectHandle obj = Activator.CreateInstance("LibraryTest", "LibraryTest.LibraryTest");
ITestInterface test = obj.Unwrap() as ITestInterface;
test.DataArrival += new DataArrival_(delegate(String Data)
    {
        Console.WriteLine("Received: " + Data);
    });
test.SendData("Hello "+ test.Name +"!!");

En este contexto, nos valen ambos planteamientos por igual, ambos cargan la instancia en el mismo dominio de aplicación que la aplicación principal y su rendimiento es bastante similar, a excepción de la primera instancia que realiza Remoting, que parece que le cuesta un poco más:

image

Pero, cuando la instancia tiene un constructor parametrizado tendrémos que usar una mezcla de las dos, ya que para poder invocar un constructor específico debemos de proveer el tipo a Activator.CreateInstance, que por supuesto lo podemos extraer con Reflection; vamos a suponer que la calse «desconocida» espera dos parámetros, un Int32 y un DataTable (ojo con el orden de los parámetros):

Assembly myAssembly = Assembly.LoadFrom("LibraryTest.dll");
Type myType = myAssembly.GetType("LibraryTest.LibraryTest");
ITestInterface test = Activator.CreateInstance(myType,myIndex,myTable) as ITestInterface;
test.DataArrival += new DataArrival_(delegate(String Data)
    {
        Console.WriteLine("Received: " + Data);
    });
test.SendData("Hello " + test.Name + "!!");

Pero… y si ni siquiera supiesemos que número de parámetros tiene el constructor… o que tipo de parámetros son… pues con Reflection podemos interrogar al tipo para que nos de información sobre los constructores que hay en la clase y sus respectivos parámetros. Un ejemplo un poco tosco :

Assembly myAssembly = Assembly.LoadFrom("LibraryTest.dll");
Type myType = myAssembly.GetType("LibraryTest.LibraryTest");
 
// Interrogo al tipo para comprobar si existe el constructor
// que necesito.
Object[] constructorParameters = null;
foreach (ConstructorInfo constructor in myType.GetConstructors())
{
    ParameterInfo[] parameters = constructor.GetParameters();
 
    if ((parameters[0].ParameterType == typeof(Int32)) &&
        parameters[1].ParameterType == typeof(DataTable))
    {
        constructorParameters = new Object[] {myIndex, myTable };
    }
    parameters.ToString();
}
 
ITestInterface test = Activator.CreateInstance(myType,constructorParameters) as ITestInterface;
test.DataArrival += new DataArrival_(delegate(String Data)
    {
        Console.WriteLine("Received: " + Data);
    });
test.SendData("Hello " + test.Name + "!!");

Como decía este es un ejemplo un poco tosco, podemos mejorar la lógica para detectar el constructor, ordenar los parámetros… etc.. etc..

Lo máximo que sabe la aplicación sobre la clase, es su nombre y en que ensamblado esta, cosas que le podemos pasar como parámetros ó tenerlo alojado en un archivo de configuración, de forma que alterando dicho archivo la aplicación usa una u otras funcionalidades. Y con esto e imaginación puedes hacer tus arquitecturas tan inteligentes y escalables como tu quieras, de forma que sean capaces de cargar tipos sin conocerlos previamente y usarlos por medio de una interfaz ó clase abstracta. Si a esto le añades el uso de atributos como metadatos para describir las clases… aún puedes conseguir cosas más inteligentes y escalables, a ver si tengo tiempo otro día para escribir sobre este tema, que es bastante apasionante 🙂

Cargar un tipo dinamicamente | vtortola.NET

Conversion de arrays sin cast directo con C#

Realizar casting entre clases es siempre sencillo, el inconveniente es cuando se trata de un arrays. Por ejemplo… sabiendo que la clase Manager deriva de Employee, si tenemos un array de Manager, es fácil convertirlo en un array de Employee usando casting directo:

Employee[] employees1 = (Employee[])managers;

Pero si tenemos un array de Employee no es posible convertirlo en  un array de Manager de la misma forma que tampoco podríamos hacer un casting directo entre objetos simples. No se me ocurre razón cuerda para querer hacer tal cosa, pero otro ejemplo más cotidiano puede ser cuando intentamos mostrar el contenido de un array en una línea usando String.Join, nos daremos cuenta que tiene que ser String[]. Existen muchas situaciones donde no hay un casting directo.

[more]

Afortunadamente disponemos del método genérico Array.ConvertAll<,> y del delegado genérico Converter<,> que nos pueden ayudar a simplificar estas cosas:

// Primero definimos como se convierte una clase en la otra
Converter<Employee, String> Employee2String = delegate(Employee m) { return m.Name; };
 
// Después convertimos todos los elementos del array usando ese delgado
String[] sArray = Array.ConvertAll<Employee,String>(Employees,Employee2String);

Ó podemos hacerlo en una sola línea aprovechando la inferencia de tipos:

String[] sArray = Array.ConvertAll<Employee,String>(Employees,delegate(Employee m) { return m.Name; });

 

Conversion de arrays sin cast directo con C# | vtortola.NET

Desechable o no desechable

La interfaz IDisposable nos provee del método .Dispose() que utilizamos para liberar los recursos que esta usando ese objeto, pero dicho método… no deja de ser un simple método 😉 Solo hace falta hacer una pequeña prueba para darse cuenta:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Desechable test = new Desechable();
   6:            
   7:          test.Dispose();
   8:   
   9:          Console.WriteLine(test.Cadena??"Muerto"); // Muestra: Vivo!
  10:          Console.ReadKey(true);
  11:      }
  12:  }
  13:   
  14:  class Desechable : IDisposable
  15:  {
  16:      public String Cadena = "Vivo!";
  17:   
  18:      public void Dispose()
  19:      {
  20:   
  21:      }
  22:  }

Ok ok… un poco más complejo:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Desechable test = new Desechable();
   6:          WeakReference wr = new WeakReference(test.Tabla.Columns[0]);
   7:   
   8:          test.Dispose();
   9:          test = null;
  10:   
  11:          Console.WriteLine(((DataColumn)wr.Target).ColumnName); // Muestra "Columna"
  12:          Console.ReadKey(true);
  13:      }
  14:  }
  15:   
  16:  class Desechable : IDisposable
  17:  {
  18:      public DataTable Tabla = new DataTable();
  19:   
  20:      public Desechable()
  21:      {
  22:          Tabla.Columns.Add(new DataColumn("Columna"));
  23:      }
  24:   
  25:      public void Dispose()
  26:      {
  27:          Tabla.Dispose();
  28:      }
  29:  }

El resultado cambia si en la línea 10 hacemos un GC.Collect() ;D

Como vemos, el único que puede liberar memoria en el .NET Framework es el Garbage Collector, por lo que el método .Dispose() no libera memoria in libera nada, solo nos sirve para asegurar que el objeto que estamos desechando ha cerrado correctamente todos sus recursos y podemos olvidarnos de él, ya se encargará el GC de liberar la memoria cuando lo crea necesario.

Entonces, implementar la interfaz IDisposable no hace nuestros objetos «destruibles» bajo demanda, ni setear todos los campos a null en Dispose no va a hacer que sea recolectado más deprisa, ni no hacerlo va a evitar que sea recolectado, ni debemos des-subscribir los eventos…

Por lo tanto, debemos implementar el patrón IDisposable en una clase siempre que:

  • Nuestra clase deriva de una clase que lo implementa.
  • Nuestra clase esta compuesta de otras clases que lo implementan.
  • Hagamos uso de recursos no administrados.

Para todo lo demás… mastercard confia en el GC 😀

Un tema que causa controversia en este aspecto es… ¿que pasa con los delegados? ¿Como el estar subscrito a delegados afecta a la recolección de memoria? Bien, el estar subscrito a un delegado de una clase, no afecta en su recolección:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          MiClase test = new MiClase();
   6:          WeakReference wr = new WeakReference(test);
   7:          
   8:          test.MiEvento += new EventHandler(test_MiEvento);
   9:   
  10:          test = null;
  11:          GC.Collect();
  12:   
  13:          Console.WriteLine(wr.IsAlive ? "Vivo" : "Muerto"); // Muestra "Muerto"
  14:          Console.ReadKey(true);
  15:      }
  16:   
  17:      static void test_MiEvento(object sender, EventArgs e)
  18:      {
  19:          throw new NotImplementedException();
  20:      }
  21:  }
  22:   
  23:  class MiClase
  24:  {
  25:      public event EventHandler MiEvento;
  26:  }

Pero al revés, es decir, que una clase este subscrita a uno de nuestros delegados… si provoca que el objeto no pueda ser recolectado:

   1:  class Program
   2:  {
   3:      static event EventHandler Evento;
   4:      static void Main(string[] args)
   5:      {
   6:          MiClase test = new MiClase();
   7:          WeakReference wr = new WeakReference(test);
   8:   
   9:          Evento += test.Manejador_Evento;
  10:   
  11:          test = null;
  12:          GC.Collect();
  13:   
  14:          Console.WriteLine(wr.IsAlive ? "Vivo" : "Muerto"); // Muestra "Vivo"
  15:          Console.WriteLine(Evento.GetInvocationList().Length); // Muestra 1
  16:          Console.ReadKey(true);
  17:      }
  18:  }
  19:   
  20:  class MiClase
  21:  {
  22:      public void Manejador_Evento(object sender, EventArgs e)
  23:      {
  24:          throw new NotImplementedException();
  25:      }
  26:  }

Y ojo, que los delegados son muy comodos para ejecutar muchos métodos de una pasada (por ejemplo podríamos tener una serie de objetos subscritos a un delegado y cada vez que invocaramos a este se ejecutaria ese método en todos los objetos), pero como veis pueden causar un memory leak; aunque en ese caso poco podemos hacer desde el método Dispose ya que es otra clase la que ha de desuscribirse.

Saludos desde el frio Dublin donde el Verano es una broma de mal gusto.

Desechable o no desechable| vtortola.NET

Constructores, inicializacion rapida de objetos y C# 3.0

La inicialización rápida de objetos es una nueva e interesante característica de C# 3.0, pero me gustaria reflexionar un poco sobre su uso y el de nuestros amigos los constructores.

Un constructor es el método de una instancia que implementa las acciones necesarias para inicializar la instancia de la clase, y es invocado por el operador new cuando instanciamos dicha clase.  Por lo tanto, cuando desarrollamos una clase, el ó los constructores deben de tener la capacidad de inicializar los aspectos básicos de funcionamiento del objeto.

En C#, cuando no implementamos ningún constructor, el compilador asume que tenemos un constructor sin parámetros, es decir, esto:

[more]

class MyClass
{
    public String Field1 { get; private set; }
    public String Field2 { get; private set; }
}

es lo mismo que esto:

class MyClass
{
    public String Field1 { get; private set; }
    public String Field2 { get; private set; }
 
    public MyClass()
    {
    }
}

En el momento que definamos un constructor con parámetros, el compilador deja de asumir la existencia del constructor sin ellos, el motivo me parece más que obvio, si definimos un constructor con parámetros estamos diciendo que nuestra clase necesita «otras cosas» para poder inicializarse correctamente; si queremos tener otro sin parámetros tendremos que definirlo explicitamente.

Una ve las ventajas de usar un constructor paramétrizado, es por ejemplo inicializar propiedades públicas con setter privado, y modificarlas desde el constructor en base a los parámetros (seguro que no lo has hecho nunca xD); pero la principal ventaja es que le dice al programador que se necesita para ser inicializado y poder empezar a trabajar. A veces no necesitamos parámetros y otras veces es inevitable y debemos definir un constructor sin parámetros, como por ejemplo para permitir la serialización en Xml.

Definir constructores es bastante llevadero y poco pesado, ya que gracias a la sobrecarga, se escriben rápido, sin repetir el código en cada uno de ellos y queda bastante claro:

class MyControl : Control
{
    public String Field1 { get; private set; }
    public String Field2 { get; private set; }
    public String Field3 { get; private set; }
 
    // base: nos permite pasar parámetros a la 
    // clase de la que heredamos
    public MyControl(Control parent, String text, String field1)
        : base(parent, text)
    {
        this.Field1 = field1;
    }
 
    // this: nos permite invocar a otro constructor
    // de la misma clase, de forma que lo que escribimos
    // en este prosigue la labor del otro, evitandonos escribir
    // otra vez lo mismo para cada constructor.
    public MyControl(Control parent, String text, String field1, String field2)
        : this(parent, text, field1)
    {
        this.Field2 = field2;
    }
 
    // this: nos permite llamar a cualquier constructor
    // de la misma clase.
    public MyControl(Control parent, String text, String field1, String field2, String field3)
        : this(parent, text, field1,field2)
    {
        this.Field3 = field3;
    }
}

También se pueden definir modificadores de acceso en los constructores, de forma que haya constructores que solo se puedan usar desde dentro de la misma clase(private), clase derivada(protected), ensamblado(internal) ó por todo el mundo(public). Útil para controlar desde donde se pueden instanciar nuestros objetos, ó cuantas veces, como en el patrón Singleton.

Además, podemos definir un constructor estático, sin parámetros, sin modificadores de acceso, imposible de invocar directamente… pero que nos permite inicializar lo que queramos antes que nigún miembro de la clase, estático ó de instancia, sea usado.

Bien, en C# 3.0 la inicialización rápida de objetos, permiten inicializar las propiedades públicas de una clase de una pasada:

class MyControl : Control
{
    public String Field1 { get;  set; }
    public String Field2 { get;  set; }
    public String Field3 { get;  set; }
    public String Field4 { get; private set; }
}
 
static void Main()
{
    MyControl mc = new MyControl() { Field1 = "f1", Field2 = "f2", Field3 = "f3" };
}

No voy a discutir de lo útil que es, porque definitivamente lo es, pero por supuesto no es una caracteristica para reemplazar los constructores porque:

  • No podemos inicializar campos privados ó propiedades públicas con setter privado.
  • Puede que necesitamos ejecutar alguna lógica ó incluso otros métodos en función del tipo de parámetros.
  • No denota cuales son las propiedades que necesita tener configuradas para poder considerarse totalmente inicializado, de cara a alguien que consuma nuestra clase a posteriori. Esto me parece lo más importante, ya que el código debe intentar ser autodescriptivo.

Al igual que los métodos parciales, métodos extensores ó tipos anónimos, es una nueva caracteristica para tener en cuenta y para usar cuando sea apropiado, no viene a reemplazar nada, viene a complementar para «esos casos» donde hace falta.

Si tu clase necesita datos ó ser inicializada, implementa un constructor parametrizado. Por la salud mental de nuestros compañeros de trabajo, hagamos un buen uso del lenguaje 😀

Constructores, inicializacion rapida de objetos y C# 3.0 | vtortola.NET

Asi da gusto usar Windows Vista

Pedazo de maquinón que estrené en el trabajo y con el que estoy más que contento, es un placer trabajar así.

image

Mi jefe es de esas personas que sabe como hacerte feliz. Después de algo más de una semana trabajando con él, cuando cojo mi portátil ya no es lo mismo… definitivamente tengo que hacerme con uno de estos para mi casa 😀

El monitor no es que se quede atrás:

image

Asi da gusto usar Windows Vista| vtortola.NET

Asistente P/Invoke Interop

Si trabajas con p/invoke tanto habitual como eventualmente y pinvoke.net esta en tus bookmarks… esta herramienta no te va a dejar indiferente 😀 Leo en el blog del BCL Team:

El equipo Interop ha publicado recientemente una nueva herramienta llamada P/Invoke Interop Assistant. Esta herramienta genera automáticamente las declaraciones en C# ó VB.NET de las llamadas p/invoke nativas. Incluye una búsqueda rápida por las librerias comunes Win32 y permite generar las declaraciones para cualquier otra libreria nativa simplemente pasando la firma nativa. Esto hace mucho más facil trabajar con interop correctamente, sin tener que comprender todas las reglas y atributos usados cuando «conecta» el desarrollo administrado y no administrado. `

image

La herramienta fue publicada en MSDN Magazine como parte del artículo Marshaling between Managed and Unmanaged Code en Enero. Ahora esta en CodePlex junto al código fuente. Altamente recomendado echarle un ojo!!

Impresionante!! La estoy usando y me va a ahorrar mucho tiempo en búsquedas 😀 Obviamente, no va a substituir a pinvoke.net porque dicha web tiene algo muy importante, ejemplos y tips (que habría sido de mi sin esta web estas dos semanas…), mientras que este programa solo te proporciona las firmas… pero esta claro que es una herramienta indispensable si se trabaja con interop 🙂

Asistente P/Invoke Interop | vtortola.NET

Recursividad y yield return. Haciendo queries a colecciones en arbol en C# 2.0

Estoy disfrutando de lo que será mi último proyecto en C# 2.0 y .NET 2.0 antes de pasar a WPF, y la verdad es que se hace amargo algunas veces cuando ya conoces C# 3.0, por ejemplo se hecha de menos LINQ 😀

En este artículo quiero demostrar como hacer queries a una colección de elementos en forma de arbol desde C# 2.0, de forma que se pueda definir el tipo de colección, criterio de búsqueda que se quiere usar y obtener los resultado conforme se vayan obteniendo.

Una función recursiva, es una función que se llama a si misma y controla cuando parar de hacerlo mediante una condición. Si esa condición no esta bien definida… a parte del cuelgue del hilo en cuestión lo más posible será terminar recibiendo una sonora StackOverflowException.

Para recorrer una estructura en arbol nada mejor que una función recursiva, un ejemplo muy simple es esta función que recorre todos los controles hijos de un control dado recursivamente:

/// <summary>
/// Recorre recursivamente todos los
/// controles hijos de un control dado.
/// </summary>
void lookRecursive(Control Parent)
{
    // Recorro los subnodos
    foreach (Control child in Parent.Controls)
    {
        Debug.Print(child.Name);
 
        // Si el subnodo tiene más subnodos
        // ejecuto recursivamente.
        if (child.Controls.Count > 0)
            lookRecursive(child);
    }
}

Podemos hacer que la función nos devuelva un elemento introduciendo una variable para el almacenamiento, si por ejemplo lo que queremos es que encuentre un determinado control por su nombre y lo devuelva (ya hay un método por ahí por la BCL que lo hace):

/// <summary>
/// Recorre recursivamente todos los
/// controles y encuentra el de un nombre
/// determinado.
/// </summary>
Control findControl(Control Parent, String Name)
{
    Control temp=null;
    // Recorro los subnodos
    foreach (Control child in Parent.Controls)
    {
        // Criterio de búsqueda
        if (child.Name == Name)
            temp = child;
        else if((temp==null) && (child.Controls.Count > 0))
            temp = findControl(child,Name);
    }
    return temp;
}

Ahora vamos a complicarlo un poco más añadiendo las siguientes características:

  • Adaptable a cualquier tipo de objetos: Usando genéricos.
  • Definir nuestro propio criterio de búsqueda: Pasando un Predicate como argumento que contenga el criterio.
  • Definir como se obtienen los sub-nodos: Pasando un delegado que lo especifique.
  • La posibilidad de que el resultado no sea único: Devolviendo una colección ó array.
  • Poder parar de recorrer cuando encontremos lo que queremos: Que la colección devuelta sea IEnumerable ó IEnumerable<T>y devolver con yield.

Asi queda:

delegate IEnumerable getChilds<T>(T Element);
IEnumerable<T> findRecursive<T>(T Parent, getChilds<T> Elements, Predicate<T> Criteria)
{
    foreach (T element in Elements.Invoke(Parent))
    {
        if (Criteria.Invoke(element))
            yield return element;
 
        foreach (T element2 in findRecursive<T>(element,Elements, Criteria))
            yield return element2;
    }
}

El delegado getChilds define como obtener subnodos de un nodo dado.

Nota: En este ejemplo, en el delegado devuelvo IEnumerable y no IEnumberable<T> (que seria lo lógico) porque Control.Controls es un ControlCollection que solo implementa dicha interfaz, no la genérica 😛

Para usarlo… por ejemplo, queremos que todos los paneles pasen a tener borde FixedSingle:

// Defino el criterio de búsqueda,
// en este caso, quiero los controles
// que sean paneles.
Predicate<Control> lookForPanels = delegate(Control c)
{
    return c is Panel;
};
 
// Defino como obtengo los hijos de 
// este tipo de objeto.
getChilds<Control> getChildControls = delegate(Control C)
{
    return C.Controls;
};
 
// Por último efectuo la búsqueda
// y obtengo los resultados.
foreach (Panel c in findRecursive<Control>(this, getChildControls, lookForPanels))
{
    c.BorderStyle = BorderStyle.FixedSingle;
}

Y si se quiere más complejo también se puede recorrer una estructura en arbol con múltiples hilos😛

Recursividad y yield return. Haciendo queries a colecciones en arbol en C# 2.0 | vtortola.NET