Si una propiedad por la reflexión con un valor de cadena
-
23-08-2019 - |
Pregunta
Me gustaría establecer una propiedad de un objeto a través de la 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);
Como es, esto arroja una ArgumentException
:
objeto de tipo 'System.String' no se puede convertir al tipo 'System.Double'.
¿Cómo puedo convertir el valor al tipo adecuado, basado en propertyInfo
?
Solución
Puede utilizar Convert.ChangeType()
- Se permite el uso de información de tiempo de ejecución en cualquier tipo IConvertible
para cambiar formatos de representación. No todas las conversiones son posibles, sin embargo, y puede que tenga que escribir la lógica de casos especiales, si quieres apoyar las conversiones de tipos que no están IConvertible
.
El código correspondiente (sin tratamiento de excepciones o lógica especial caso) 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);
Otros consejos
Como muchos otros han dicho, que desea utilizar Convert.ChangeType
:
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
De hecho, le recomiendo que busque en toda la Convert
Clase .
Esta clase, y muchas otras clases útiles son parte de la System
Espacio de nombres . Me resulta útil para explorar ese espacio de nombres o menos cada año para ver qué características que he perdido. Darle una oportunidad!
Me he dado cuenta de una gran cantidad de personas están recomendando Convert.ChangeType
- Esto funciona para algunos casos, sin embargo, tan pronto como se inicia la participación de tipos nullable
usted comenzará a recibir InvalidCastExceptions
:
Una envoltura fue escrito hace unos años para manejar esto, pero que tampoco es perfecta.
Puede utilizar 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 cuanto a la organización del código, se puede 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
se puede reutilizar para muchas clases diferentes.
También puede crear su propia tipo convertidores adjuntar a sus propiedades o clases:
public class Ship : MPropertyAsStringSettable {
public Latitude Latitude { get; set; }
// ...
}
[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
Probé la respuesta de LBushkin y funcionó muy bien, pero no va a funcionar para valores nulos y anulables campos. Así que 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);
}
Probablemente se esté buscando la href="http://msdn.microsoft.com/en-us/library/dtb69x08.aspx" rel="noreferrer"> 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);
El uso de Convert.ChangeType
y obtener el tipo de convertir de la PropertyInfo.PropertyType
.
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
Voy a responder a esto con una respuesta general. Por lo general, estas respuestas no se trabaja con guids. Aquí está 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);
O usted podría intentar:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
Si está escribiendo metro aplicación, se debe utilizar otro tipo de 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");
Usando el siguiente código debería resolver el problema:
item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));
¿Está buscando para jugar un poco con la reflexión o está buscando para construir una pieza de producción de software? Me pregunta por qué estás usando la reflexión para establecer una propiedad.
Double new_latitude;
Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;