Establecer una propiedad por reflexión con un valor de cadena


Me gustaría establecer una propiedad de un objeto a través de Reflexión, con un valor de tipo string. Así, por ejemplo, supongamos que tengo una clase Ship, con una propiedad de Latitude, que es un double.

Esto es lo que me gustaría hacer:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, value, null);

Tal como está, esto arroja un ArgumentException:

Objeto de tipo 'System.Cadena 'no se puede convertir a tipo' Sistema.Doble.

¿Cómo puedo convertir el valor al tipo adecuado, basado en propertyInfo?

Author: Irshad, 2009-07-07

11 answers

Puede utilizar Convert.ChangeType() - Le permite usar información de tiempo de ejecución en cualquier tipo IConvertible para cambiar los formatos de representación. Sin embargo, no todas las conversiones son posibles, y es posible que deba escribir una lógica de mayúsculas y minúsculas especial si desea admitir conversiones de tipos que no son IConvertible.

El código correspondiente (sin manejo de excepciones o lógica de casos especiales) sería:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
 447
Author: LBushkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 08:31:45

Como muchos otros han dicho, quieres usar Convert.ChangeType:

propertyInfo.SetValue(ship,
    Convert.ChangeType(value, propertyInfo.PropertyType),
    null);

De hecho, le recomiendo que mire todo el Convert Clase .

Esta clase, y muchas otras clases útiles son parte de la System espacio de Nombres. Me resulta útil escanear ese espacio de nombres cada año más o menos para ver qué características me he perdido. ¡Inténtalo!

 31
Author: John Saunders,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 08:57:13

Noto que mucha gente está recomendando Convert.ChangeType - Esto funciona para algunos casos, sin embargo, tan pronto como comience a involucrar nullable tipos comenzará a recibir InvalidCastExceptions:

Http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx

Hace unos años se escribió un wrapper para manejar esto, pero eso tampoco es perfecto.

Http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx

 18
Author: Tablet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 09:09:27

Puede usar un convertidor de tipos (sin comprobación de errores):

Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);

En términos de organizar el código, podría crear un tipo de mixin que resultaría en código como este:

Ship ship = new Ship();
ship.SetPropertyAsString("Latitude", "5.5");

, Esto se lograría con este código:

public interface MPropertyAsStringSettable { }
public static class PropertyAsStringSettable {
  public static void SetPropertyAsString(
    this MPropertyAsStringSettable self, string propertyName, string value) {
    var property = TypeDescriptor.GetProperties(self)[propertyName];
    var convertedValue = property.Converter.ConvertFrom(value);
    property.SetValue(self, convertedValue);
  }
}

public class Ship : MPropertyAsStringSettable {
  public double Latitude { get; set; }
  // ...
}

MPropertyAsStringSettable puede ser reutilizado para muchas clases diferentes.

También puede crear sus propios convertidores de tipo personalizados para adjuntarlos a sus propiedades o clases:

public class Ship : MPropertyAsStringSettable {
  public Latitude Latitude { get; set; }
  // ...
}

[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
 11
Author: Jordão,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-15 10:48:55

Probablemente estés buscando el Convert.ChangeType método. Por ejemplo:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
 6
Author: John Calsbeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-06 20:48:30

Usando Convert.ChangeType y obteniendo el tipo a convertir de PropertyInfo.PropertyType.

propertyInfo.SetValue( ship,
                       Convert.ChangeType( value, propertyInfo.PropertyType ),
                       null );
 5
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-06 08:47:06

Probé la respuesta de LBushkin y funcionó muy bien, pero no funcionará para valores null y campos nullables. Así que lo he cambiado a esto:

propertyName= "Latitude";
PropertyInfo propertyInfo = ship.GetType().GetProperty(propertyName);
if (propertyInfo != null)
{
     Type t = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
     object safeValue = (value == null) ? null : Convert.ChangeType(value, t);
     propertyInfo.SetValue(ship, safeValue, null);
}
 4
Author: Ashkan Sirous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-04 14:51:33

O puedes intentar:

propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);

//But this will cause problems if your string value IsNullOrEmplty...
 3
Author: bytebender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-06 20:47:37

Si está escribiendo la aplicación Metro, debe usar otro código:

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));

Nota:

ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");

En lugar de

ship.GetType().GetProperty("Latitude");
 2
Author: Serhiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-10 08:22:55

Responderé esto con una respuesta general. Por lo general, estas respuestas no funcionan con guid. Aquí hay una versión de trabajo con guids también.

var stringVal="6e3ba183-89d9-e611-80c2-00155dcfb231"; // guid value as string to set
var prop = obj.GetType().GetProperty("FooGuidProperty"); // property to be setted
var propType = prop.PropertyType;

// var will be type of guid here
var valWithRealType = TypeDescriptor.GetConverter(propType).ConvertFrom(stringVal); 
 1
Author: Ali Karaca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-30 08:35:04

¿Está buscando jugar con la reflexión o está buscando construir una pieza de producción de software? Me preguntaría por qué estás usando reflexión para establecer una propiedad.

Double new_latitude;

Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;
 -7
Author: clemahieu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-06 20:57:55