Crear una instancia de una clase a partir de una cadena

217

¿Hay alguna manera de crear una instancia de una clase basada en el hecho de que sé el nombre de la clase en tiempo de ejecución? Básicamente, tendría el nombre de la clase en una cadena.

PeteT
fuente
Parece que ha descrito la solución que desea implementar, pero no el problema que está tratando de resolver. Quizás esté intentando hacer algo con la extensibilidad, en cuyo caso le sugiero que consulte el Marco de Extensibilidad Administrada .
Jay Bazuzi

Respuestas:

159

Eche un vistazo al método Activator.CreateInstance .

Matt Hamilton
fuente
15
Relacionado con excelentes ejemplos: stackoverflow.com/questions/493490/…
John S.
También esta publicación también será relevante, ya que su tipo necesita ser encontrado: stackoverflow.com/questions/1825147/…
Brad Parks
1
Ejemplos: stackoverflow.com/questions/7598088/…
profimedica
44
Por ejemplo:var driver = (OpenQA.Selenium.IWebDriver)Activator.CreateInstance("WebDriver", "OpenQA.Selenium.Firefox.FirefoxDriver").Unwrap();
Endy Tjahjono
2
Nota importante aquí: .Unwrap () para pasar el control remoto para que puedas hacer los lanzamientos. @Endy - Gracias
Roger Willcocks
77

Es muy simple. Suponga que su nombre de clase es Cary el espacio de nombres es Vehicles, luego pase el parámetro Vehicles.Carque devuelve el objeto de tipo Car. De esta manera, puede crear cualquier instancia de cualquier clase de forma dinámica.

public object GetInstance(string strFullyQualifiedName)
{         
     Type t = Type.GetType(strFullyQualifiedName); 
     return  Activator.CreateInstance(t);         
}

Si su nombre completo (es decir, Vehicles.Caren este caso) está en otro conjunto, Type.GetTypeserá nulo. En tales casos, usted tiene bucle a través de todos los conjuntos y encontrar el Type. Para eso puedes usar el siguiente código

public object GetInstance(string strFullyQualifiedName)
{
     Type type = Type.GetType(strFullyQualifiedName);
     if (type != null)
         return Activator.CreateInstance(type);
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
     {
         type = asm.GetType(strFullyQualifiedName);
         if (type != null)
             return Activator.CreateInstance(type);
     }
     return null;
 }

Ahora, si desea llamar a un constructor parametrizado, haga lo siguiente

Activator.CreateInstance(t,17); // Incase you are calling a constructor of int type

en vez de

Activator.CreateInstance(t);
Sarath Avanavu
fuente
¿Cómo usarlo sin lanzar y cómo hacer el lanzamiento desde la cadena dada ?
TaW
1
@TaW: para usar una instancia de clase, necesitará tener algún conocimiento de lo que va a hacer; de lo contrario, no podrá usarla. El caso de uso más común para esto sería transmitir a alguna interfaz que le otorgue un contrato predefinido. (Esto se mantiene a menos que esté usando dynamiccódigo; consulte stackoverflow.com/a/2690661/904521 )
Tomer Cagan,
1
No codificar el tipo de la variable en su nombre, por ejemplo:. No hay necesidad de prefijo strFullyQualifiedNamecon str, fullyQualifiedNamehará el trabajo.
Mehdi Dehghani
La palabra clave strse usa como parte de la convención de nomenclatura para variables. Ciertas organizaciones y proyectos insisten en seguir esto, por lo tanto, solía. Si hubiera trabajado en ciertas organizaciones / proyectos, lo sabrá. Como dijiste sin, strtambién hará el trabajo :) @MehdiDehghani
Sarath Avanavu
1
Lo sé, sin embargo, no es necesario trabajar en ninguna organización para conocer las convenciones de nomenclatura, esta convención conocida como notación húngara y es una de las convenciones de nomenclatura malas y obsoletas que existen. especialmente para C #
Mehdi Dehghani
55

He usado este método con éxito:

System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(string className)

Deberá convertir el objeto devuelto en el tipo de objeto deseado.

Ray Li
fuente
99
Estoy tratando de imaginar un escenario en el que crear el objeto mediante el nombre de la clase y luego convertirlo en ese tipo tenga sentido.
MusiGenesis
13
Veo a que te refieres. Parece redundante Si conoce el nombre de la clase, ¿por qué necesita la cadena dinámica? Una situación podría ser que su conversión a una clase base y la cadena representan descendientes de esa clase base.
Ray Li
44
Si se conoce la clase base, puede usar la clase base o una interfaz de la misma como argumento para pasar descendientes sin reflexión.
Garet Claborn
3
Escenario útil: solo necesita las interfaces de serialización, o cualquier otra interfaz bastante común. No lo
lanzarás
2
¿Cómo hacer el reparto desde la cadena dada ?
TaW
23

Probablemente mi pregunta debería haber sido más específica. De hecho, conozco una clase base para la cadena, así que la resolví:

ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

La clase Activator.CreateInstance tiene varios métodos para lograr lo mismo de diferentes maneras. Podría haberlo lanzado a un objeto, pero lo anterior es de gran utilidad para mi situación.

PeteT
fuente
44
En lugar de responder en la sección de preguntas, le sugiero que edite su pregunta y tenga en cuenta los cambios. Obtendrá más / mejores respuestas por hacerlo.
Jason Jackson
Gracias por publicar la línea de código específica que funcionó para usted. La clasificación de todas las sobrecargas de CreateInstance y las diferentes formas de generar Tipos me llevó mucho tiempo, lo que me salvó.
Ethel Evans
4

Sé que llego tarde al juego ... pero la solución que estás buscando podría ser la combinación de lo anterior, y el uso de una interfaz para definir tus objetos de acceso público.

Luego, si todas las clases que se generarían de esta manera implementan esa interfaz, puede convertir como tipo de interfaz y trabajar con el objeto resultante.

Denny
fuente
4

Para crear una instancia de una clase desde otro proyecto en la solución, puede obtener el ensamblado indicado por el nombre de cualquier clase (por ejemplo, BaseEntity) y crear una nueva instancia:

  var newClass = System.Reflection.Assembly.GetAssembly(typeof(BaseEntity)).CreateInstance("MyProject.Entities.User");
asd
fuente
3

Por ejemplo, si almacena valores de varios tipos en un campo de base de datos (almacenado como una cadena) y tiene otro campo con el nombre del tipo (es decir, String, bool, int, MyClass), entonces, a partir de los datos de ese campo, podría, posiblemente, cree una clase de cualquier tipo con el código anterior y complétela con el valor del primer campo. Esto, por supuesto, depende del tipo que esté almacenando con un método para analizar cadenas en el tipo correcto. Lo he usado muchas veces para almacenar la configuración de preferencias del usuario en una base de datos.

Greg Osborne
fuente
-11
ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));

¿Por qué quieres escribir un código como este? Si tiene una clase 'ReportClass' disponible, puede instanciarla directamente como se muestra a continuación.

ReportClass report = new ReportClass();

El código ReportClass report = (ReportClass)Activator.CreateInstance(Type.GetType(reportClass));se utiliza cuando no tiene disponible la clase necesaria, pero desea crear una instancia o invocar un método de forma dinámica.

Quiero decir que es útil cuando conoces el ensamblado, pero al escribir el código no tienes la clase ReportClassdisponible.

Asish
fuente