¿Cómo generar una instancia de un tipo desconocido en tiempo de ejecución?

Tengo lo siguiente en C #:

string typename = "System.Int32"; string value = "4"; 

estas dos cadenas deben tomarse para generar un objeto del tipo especificado con el valor especificado …

el resultado debe ser:

 object o = CreateUnknownType(typename, value); ... Int32 test = (Int32)o; 

¿Es esto lo que estás pensando?

 object result = Convert.ChangeType("4", Type.GetType("System.Int32")); 

Como se dijo, esto es demasiado amplio y no se puede resolver en general.

Aquí hay algunas opciones:

 Type type = Type.GetType(typename); object o = Activator.CreateInstance(type); 

Esto creará una instancia del tipo que describe typename . Se llama el constructor sin parámetros de ese tipo. (Aspecto negativo: no todos los objetos tienen un constructor sin parámetros. Además, esto establece el estado del objeto utilizando un value ).

 Type type = Type.GetType(typename); object o = Activator.CreateInstance(type, new[] { value }); 

Esto creará una instancia del tipo que describe typename . Llama a un constructor de ese tipo que acepta un parámetro de tipo string . (Aspecto negativo: no todos los objetos tienen un constructor de este tipo. Por ejemplo, Int32 no tiene dicho constructor, por lo que experimentará una excepción de tiempo de ejecución).

 Type type = Type.GetType(typename); object o = Convert.ChangeType(value, type); 

Esto intentará convertir el value cadena en una instancia del tipo requerido. Esto puede llevar a InvalidCastException s sin embargo. Por ejemplo, Convert.ChangeType("4", typeof(FileStream)) obviamente fallará, como debería.

De hecho, este último ejemplo (crear una instancia de tipo FileStream con su estado inicial determinado por la cadena "4" ) muestra cuán absurdo es el problema general. Hay algunas construcciones / conversiones que simplemente no se pueden hacer.

Es posible que desee repensar el problema que está tratando de resolver para evitar este embrollo.

Creando una instancia de un tipo que conoces por nombre (y que debería tener un constructor predeterminado):

  string typeName = "System.Int32"; Type type = Type.GetType(type); object o = Activator.CreateInstance(type); 

El análisis de un valor de una cadena obviamente solo funcionará para un conjunto limitado de tipos. Tú podrías

  • use Convert.ChangeType como lo sugiere PhilipW
  • o tal vez cree un Dictionary> que asigne tipos conocidos a funciones de análisis conocidas
  • o use la reflexión para invocar el método Parse (cadena) en el tipo, asumiendo que hay uno:

      string valueText = "4"; MethodInfo parseMethod = type.GetMethod("Parse"); object value = parseMethod.Invoke(null, new object[] { valueText }); 
  • o tal vez puede utilizar la infraestructura proporcionada por el modelo de componente .NET. Puede obtener el convertidor de tipos de un componente y usarlo así:

      TypeConverter converter = TypeDescriptor.GetConverter(type); object value = converter.ConvertFromString(valueText); 

Tu lógica parece un poco defectuosa aquí. Obviamente, si está convirtiendo el objeto directamente en un momento posterior al tipo real que es, entonces debe saber el tipo para comenzar.

Si hay algo más que falta en esta pregunta, por favor, elabore y quizás haya una respuesta más apropiada que simplemente: “Esto no tiene mucho sentido”.

¿Quizás tenga un conjunto de diferentes tipos, todos los cuales implementan una interfaz conocida?

Por ejemplo, si tiene varios controles de usuario diferentes y desea cargar uno de ellos en un contenedor, cada uno podría implementar IMyWobblyControl (una interfaz conocida), sin embargo, es posible que no sepa hasta qué tiempo de carga cuál de ellos cargar, posiblemente al leer cadenas de alguna forma. de archivo de configuración.

En ese caso, necesitará usar la reflexión para cargar el tipo real de algo como el nombre completo del ensamblaje, luego conviértalo en su tipo conocido para usarlo.

Por supuesto, debe asegurarse de que su código maneje la conversión no válida, el ensamblaje no encontrado y cualquiera de las demás excepciones que puedan surgir a través de algo tan inestable como este …

Esto parece ser un trabajo para Int32.Parse (cadena). Pero para estar de acuerdo con los demás, parece que esto es “único” y probablemente uno debería pensar en guantes.

Aquí hay un ejemplo específico del problema relacionado con las federaciones SQL de Azure … que divide los datos en db separados de acuerdo con un rango clave.

Los tipos de rango clave son:

SQL / .Net Tipo de SQL / CLR .Net

INT / SqlInt32 / Int32, anulable

BIGINT / SqlInt64 / Int64, anulable

UNIQUEIDENTIFIER / SqlGuid / Guid, Nullable

VARBINARIO (n), máximo n 900 / SqlBytes, SqlBinary / Byte []

Idealmente, un parámetro de función de C # podría tomar el tipo .Net SQL o el tipo CLR .Net, pero no está mal para una sola categoría.

¿Sería un parámetro de tipo “objeto” el camino a seguir? Y, ¿hay una manera viable de identificar el tipo y convertirlo en consecuencia?

El concepto es algo como:

public void fn (objeto obj, string fedName, string distName, bool filteringOn)

{

… averiguar qué tipo de obj es asegurar que sea uno de los tipos aceptables …

clave de cadena = obj.toString ();

return string.Format (“USE FEDERATION {0} ({1} = ‘{2}’) WITH RESET, FILTERING = {3}”, fedName, distName, key, (filteringOn? “ON”: “OFF”)) ;

}

Aunque el valor param se convierte en una cadena, se revisará / verificará en el lado del servidor SQL, por lo que se desea validarlo en el lado de la aplicación.

Después de usar:

 Type type = Type.GetType(typename); 

Pruebe este método de extensión:

 public static class ReflectionExtensions { public static T CreateInstance(this Type source, params object[] objects) where T : class { var cons = source.GetConstructor(objects.Select(x => x.GetType()).ToArray()); return cons == null ? null : (T)cons.Invoke(objects); } } 

Espero que esto ayude.