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);
}