Código de cómo instanciar una clase a partir del contenido de una cadena (C#)

 

Lo dicho el código completo para Visual Basic del ejemplo comentado en:

Crear un objeto a partir de una cadena con Activator.CreateInstance

(el enlace al de Visual Basic está en ese mismo artículo)

 

//-----------------------------------------------------------------------------
// Crear un objeto a partir de una cadena con Activator             (05/Ene/13)
//
//
// ©Guillermo 'guille' Som, 2013
//-----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;

namespace ActivatorCS
{
    public sealed class CrearClase
    {

        public static void Main()
        {
            // La clase a crear
            var elNombre = "ActivatorCS.Colega";

            crearColega(elNombre);


            // Esta clase se llama igual,
            // pero no es del mismo tipo
            // y no pasaría la prueba de IsAssignableFrom,
            // aunque no daría error al hacer la conversión
            // pero no crearía una instancia,
            // por tanto Activator devolvería nulo,
            // en realidad el valor nulo lo devuelve
            // la operación de conversión de tipos
            // por eso en C# utilizo "as Colega" en lugar de "(Colega)"
            // para hacer la conversión
            elNombre = "OtroEspacio.Colega";
            crearColega(elNombre);

            // esta clase se basa en la que queremos crear
            // aunque esté en otro espacio de nombres
            elNombre = "OtroEspacio.Coleguilla";
            crearColega(elNombre);

            // este tipo no existe,
            // pero debemos usar IsAssignableFrom
            // para no provocar una excepción
            elNombre = "Activator.Colega";
            crearColega(elNombre);

            // esta se basa en la nuestra
            // pero es abstracta (no tiene constructor)
            // ya dará un error al crearla
            // aunque pasaría la prueba de IsAssignableFrom
            try
            {
                elNombre = "ActivatorCS.ColegaAbstracto";
                crearColega(elNombre);

            }
            catch (Exception ex)
            {
                Console.WriteLine("Mrw! (o Ups!) esta clase {0} da error: {1}",
                                  elNombre, ex.Message);

            }

            Console.ReadKey();

        }

        private static void crearColega(string laClase)
        {
            Type elTipo = Type.GetType(laClase);

            // el equivalente en c# de TryCast es hacer el cast con "as tipo"
            // aunque también se puede comprobar si se puede crear el objeto

            // Esto contralará las clases que no se basan en Colega
            if (!typeof(Colega).IsAssignableFrom(elTipo))
            {
                Console.WriteLine("El tipo: {0} no es del tipo adecuado.\n", 
                                  laClase);
                return;
            }

            Colega obj = Activator.CreateInstance(elTipo) as Colega;

            if (obj != null)
            {
                obj.Nombre = "Pepe";
                obj.Email = "pepe@outlook.com";

                Console.WriteLine("Objeto creado correctamente: {0}{1}{2}, {3}",
                                  obj.GetType().Name, "\r\n",
                                  obj.Nombre, obj.Email);
            }
            else
            {
                Console.WriteLine("Parece que el tipo: {0} no es del tipo adecuado.", 
                                  laClase);
            }

            Console.WriteLine();
        }

        void pruebaDirecta()
        {
            var laClase = "ActivatorCS.Colega";

            Type elTipo = Type.GetType(laClase);

            Colega obj = Activator.CreateInstance(elTipo) as Colega;

            if (obj != null)
            {
                obj.Nombre = "Pepe";
                obj.Email = "pepe@outlook.com";
            }

        }

        static void Main2()
        {
            var laClase = "ActivatorVB.unColega";

            Type elTipo = Type.GetType(laClase);

            IColega obj = ((IColega)Activator.CreateInstance(elTipo));

            if (obj != null)
            {
                obj.Nombre = "Pepe";
            }
        }  

    }

    public interface IColega
    {
        string Nombre { get; set; }
    }

    public class unColega : IColega
    {
        public string Nombre { get; set; }
    }


    public class Colega
    {
        public string Nombre { get; set; }
        public string Email { get; set; }
    }

    // Clase no instanciable
    public abstract class ColegaAbstracto : Colega
    {
        public int Edad { get; set; }
    }

}

namespace OtroEspacio
{

    public class Colega
    {
        public string Nombre { get; set; }
        public int Edad { get; set; }
    }

    public class Coleguilla : ActivatorCS.Colega
    {
        public int Edad { get; set; }
    }

    // las clase selladas (sealed / NotInheritable)
    // se pueden usar, pero siempre deben tener
    // un constructor público sin parámetros
    public sealed class Coleguilla2 : ActivatorCS.Colega
    {

        //protected Coleguilla2()
        //{ 
        //}

        //private Coleguilla2()
        //{
        //}

        public int Edad { get; set; }
    }

}

 

Nos vemos.

Guillermo

Esta entrada fue publicada en cosas técnicas, mis cosas y etiquetada , , , . Guarda el enlace permanente.

8 respuestas a Código de cómo instanciar una clase a partir del contenido de una cadena (C#)

  1. Julio Valencia dijo:

    Hola Guillermo, saludos de Ecuador, sabes es interesante tu post, pero no se si te puedo molestar al ponerte un reto (mas que reto en realidad es una petición jeje).

    En tu ejemplo de todas maneras necesitas tener la clase cuando haces algo como

    Colega obj = Activator.CreateInstance(elTipo) as Colega;

    Como podrias hacer lo mismo si digamos nunca sabes que vas a recibir colega, pero claro la clase existe en tu assembly.

  2. elGuille dijo:

    Hola, no me lo he planteado nunca, puede que probara algo al principio de empezar con .net, pero de esto hace ya más de 10 años y ¡no me acuerdo! 😉
    Pero supongo que se podrá hacer… lo más que probé fue a “compilar” código al vuelo…

    De todas formas, me lo apunto a ver si encuentro la forma.
    Esto lo he hecho porque estaba usando un código en el que no sé de antemano el nombre de la clase, pero como están derivadas de una misma clase base, simplemente he usado esa clase base para hacer el “cast”.

  3. elGuille dijo:

    pensando un poco… en realidad es de la misma forma, pero sin hacer la conversión y por tanto devolviendo un object; pero al no hacer el casting no podremos usar los métodos/miembros de la clase de forma “directa”, además en C# tendrás que usar dynamic y en VB habría que tener desactivada Option Strict.
    De todas formas, lo comprobaré… no vaya a ser que… 😉

  4. elGuille dijo:

    ya he puesto el código, en:
    Si utilizas dynamic en C# acuérdate de agregar una referencia a Microsoft.CSharp
    Lo que yo te decía, usando dynamic.

    El problema es que si no “conoces” el tipo… ¿cómo lo vas a usar?

  5. Ada dijo:

    Disculpe como se crea una clase en C# en windows fomrs….? 😀

  6. elGuille dijo:

    Ada, en mi sitio: http://www.elguille.info tienes un tutorial muy bueno para iniciarte en C#

  7. Diego Bernal dijo:

    namespace DAL.Impl.SQLServer
    {
    public abstract class SQLDALAdapter : DALSQLImplementation
    {
    protected override sealed IDataBaseSQLHelper GetDataBaseHelper()
    {
    return SqlServerHelper.GetInstace();
    }

    }
    }

  8. Diego Bernal dijo:

    private SqlServerHelper() { }
    public static SqlServerHelper GetInstace()
    {
    lock (syncRoot)
    {
    if (instance == null)
    {
    instance = new SqlServerHelper();
    }
    }
    return instance;
    }

Los comentarios están cerrados.