c# - property - Establecer una propiedad por reflexión con un valor de cadena
set value property c# (11)
¿Está buscando jugar con Reflection o está buscando construir una pieza de software de producción? Me preguntaría por qué está utilizando la reflexión para establecer una propiedad.
Double new_latitude;
Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;
Me gustaría establecer una propiedad de un objeto a través de Reflexión, con un valor de tipo string . Entonces, por ejemplo, supongamos que tengo una clase de 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 está, esto lanza una ArgumentException :
El 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 ?
Como muchos otros han dicho, usted quiere usar Convert.ChangeType :
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
De hecho, te recomiendo que mires toda la Clase Convert .
Esta clase y muchas otras clases útiles forman parte del espacio de nombres del System . Encuentro útil escanear ese espacio de nombres cada año para ver qué características me he perdido. ¡Darle una oportunidad!
Me he dado cuenta de que muchas personas están recomendando Convert.ChangeType : esto funciona para algunos casos, sin embargo, tan pronto como comience a utilizar tipos nullable , comenzará a recibir las InvalidCastExceptions :
Hace unos años se escribió una envoltura para manejar esto, pero eso tampoco es perfecto.
O podrías intentar:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
Probablemente estés buscando el método Convert.ChangeType . 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);
Puede usar 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 caso 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);
Puede utilizar un convertidor de tipo (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 una especie de mezcla que resultaría en un 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 sus propios convertidores de tipos personalizados para adjuntarlos a sus propiedades o clases:
public class Ship : MPropertyAsStringSettable {
public Latitude Latitude { get; set; }
// ...
}
[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
Responderé a esto con una respuesta general. Por lo general estas respuestas no funcionan con guids. Aquí está una versión de trabajo con guías 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);
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");
Usando Convert.ChangeType y obteniendo el tipo para convertir desde PropertyInfo.PropertyType .
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
Probé la respuesta de LBushkin y funcionó muy bien, pero no funcionará para valores nulos y campos anulables. 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);
}