2010-01-19 12 views
25

En mi código de reflexión encuentro un problema con mi sección genérica de código. Específicamente cuando uso una cadena.¿Cómo uso Activator.CreateInstance con cadenas?

var oVal = (object)"Test"; 
var oType = oVal.GetType(); 
var sz = Activator.CreateInstance(oType, oVal); 

Excepción

An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll 

Additional information: Constructor on type 'System.String' not found. 

yo probamos este para propósitos de prueba y que se produce en este único revestimiento demasiado

var sz = Activator.CreateInstance("".GetType(), "Test"); 

escribí originalmente

var sz = Activator.CreateInstance("".GetType()); 

pero me sale esto error

Additional information: No parameterless constructor defined for this object. 

¿Cómo creo una cadena usando la reflexión?

Respuesta

36

Tenga en cuenta que la clase string es inmutable. No puede ser cambiado después de haber sido creado. Eso explica por qué no tiene un constructor sin parámetros, nunca podría generar un objeto de cadena útil que no sea una cadena vacía. Eso ya está disponible en el lenguaje C#, es "".

Se aplica el mismo razonamiento para un constructor de cadenas (cadenas). No tiene sentido duplicar una cadena, la cadena que pasaría al constructor ya es una instancia perfectamente buena de la cadena.

Así arreglar el problema mediante el ensayo para el caso cadena:

var oType = oVal.GetType(); 
if (oType == typeof(string)) return oVal as string; 
else return Activator.CreateInstance(oType, oVal); 
+2

Entiendo ahora. Esperaba no hacer una declaración if o algún cheque especial. Parece que debo. –

+2

Gracias. ¿Hay otras clases que puedan demostrar este problema? o, ¿puedo resolver el problema en general (para cualquier tipo arbitrario?) –

5

Usted está tratando de hacer esto:

var sz = new string(); 

intenta compilar, comprenderá su error.

Puede intentar:

var sz = Activator.CreateInstance(typeof(string), new object[] {"value".ToCharArray()}); 

Pero parece inútil, se debe utilizar directamente el valor ...

+0

En realidad, él está tratando 'var s = new String ("Test")' – leppie

+1

yo estaba hablando de esta línea: (. "" GetType()) var SZ = Activator.CreateInstance; – Guillaume

2

Parece que está intentando llamar a un constructor, que sólo se necesita una cadena - y no hay tal constructor Si ya tiene tiene una cadena, ¿por qué está tratando de crear una nueva? (Cuando no proporcionó más argumentos, estaba intentando llamar a un constructor sin parámetros, lo que tampoco existe).

Tenga en cuenta que typeof(string) es una forma más sencilla de obtener una referencia al tipo de cadena.

¿Podría darnos más información sobre la imagen más amplia de lo que está tratando de hacer?

+0

Estoy leyendo objetos a través de reflection y sqlitedatareader. No sé si oval es una cadena a menos que escriba una declaración if que quería evitar. También estoy usando fieldtype y puedo estar creando un objeto que tome una cadena. las cadenas de mención de nobugz son inmutables, así que supongo que debo escribir una instrucción if para verificar si fieldtype es una cadena o no. –

+4

Comparado con el otro hacker involucrado en la reconstrucción de objetos a partir de cadenas, creo que una simple comprobación de "ya es una cadena" probablemente sea la menor de tus preocupaciones :) –

2

Cadena en realidad no tiene ningún constructor que toma una cadena como entrada. Hay un constructor que toma una matriz de caracteres así que esto debería funcionar:

var sz = Activator.CreateInstance ("".GetType(), "Test".ToCharArray()); 
2

Esto es lo que uso en mis proyectos. En cuanto a la necesidad de crear una instanciación de un tipo de objeto y no saber en tiempo de diseño, es bastante normal para mí. Tal vez esté recorriendo las propiedades de los objetos y quiera instanciarlos dinámicamente.He necesitado muchas veces crear y luego asignar valores a objetos POCO no instanciados ... con el siguiente código puede usar un valor de cadena almacenado en el DB para instanciar un objeto también o crear una instancia de un objeto almacenado en una biblioteca que hace referencia a su biblioteca, por lo que también puede eludir errores de referencia circulares ... Espero que ayude.

using System; 
using System.Collections.Generic; 
using System.Globalization; 
using System.Reflection; 

/// <summary> 
/// Instantiates an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate 
/// returns instantiated object 
/// </summary> 
/// <param name="typeName"></param> 
/// <returns></returns> 
public static object Create(string typeAssemblyQualifiedName) 
{ 
    // resolve the type 
    Type targetType = ResolveType(typeAssemblyQualifiedName); 
    if (targetType == null) 
    throw new ArgumentException("Unable to resolve object type: " + typeAssemblyQualifiedName); 

    return Create(targetType); 
} 

/// <summary> 
/// create by type of T 
/// </summary> 
/// <typeparam name="T"></typeparam> 
/// <returns></returns> 
public static T Create<T>() 
{ 
    Type targetType = typeof(T); 
    return (T)Create(targetType); 
} 

/// <summary> 
/// general object creation 
/// </summary> 
/// <param name="targetType"></param> 
/// <returns></returns> 
public static object Create(Type targetType) 
{ 
    //string test first - it has no parameterless constructor 
    if (Type.GetTypeCode(targetType) == TypeCode.String) 
    return string.Empty; 

    // get the default constructor and instantiate 
    Type[] types = new Type[0]; 
    ConstructorInfo info = targetType.GetConstructor(types); 
    object targetObject = null; 

    if (info == null) //must not have found the constructor 
    if (targetType.BaseType.UnderlyingSystemType.FullName.Contains("Enum")) 
     targetObject = Activator.CreateInstance(targetType); 
    else 
     throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Constructor not found"); 
    else 
    targetObject = info.Invoke(null); 

    if (targetObject == null) 
    throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Unknown Error"); 
    return targetObject; 
} 

/// <summary> 
/// Loads the assembly of an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate 
/// Returns the object type. 
/// </summary> 
/// <param name="typeString"></param> 
/// <returns></returns> 
public static Type ResolveType(string typeAssemblyQualifiedName) 
{ 
    int commaIndex = typeAssemblyQualifiedName.IndexOf(","); 
    string className = typeAssemblyQualifiedName.Substring(0, commaIndex).Trim(); 
    string assemblyName = typeAssemblyQualifiedName.Substring(commaIndex + 1).Trim(); 

    if (className.Contains("[]")) 
    className.Remove(className.IndexOf("[]"), 2); 

    // Get the assembly containing the handler 
    Assembly assembly = null; 
    try 
    { 
    assembly = Assembly.Load(assemblyName); 
    } 
    catch 
    { 
    try 
    { 
     assembly = Assembly.LoadWithPartialName(assemblyName);//yes yes this is obsolete but it is only a backup call 
    } 
    catch 
    { 
     throw new ArgumentException("Can't load assembly " + assemblyName); 
    } 
    } 

    // Get the handler 
    return assembly.GetType(className, false, false); 
} 
Cuestiones relacionadas