I'd like to set a property of an object through Reflection, with a value of type string
.
So, for instance, suppose I have a Ship
class, with a property of Latitude
, which is a double
.
Here's what I'd like to do:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, value, null);
As is, this throws an ArgumentException
:
Object of type 'System.String' cannot be converted to type 'System.Double'.
How can I convert value to the proper type, based on propertyInfo
?
To set property values via Reflection, you must use the Type. GetProperty() method, then invoke the PropertyInfo. SetValue() method. The default overload that we used accepts the object in which to set the property value, the value itself, and an object array, which in our example is null.
To set the value of an indexed property, call the SetValue(Object, Object, Object[]) overload. If the property type of this PropertyInfo object is a value type and value is null , the property will be set to the default value for that type.
GetProperty(String, BindingFlags, Binder, Type, Type[], ParameterModifier[]) Searches for the specified property whose parameters match the specified argument types and modifiers, using the specified binding constraints. GetProperty(String) Searches for the public property with the specified name.
The main value of Reflection is that it can be used to inspect assemblies, types, and members. It's a very powerful tool for determining the contents of an unknown assembly or object and can be used in a wide variety of cases.
You can use Convert.ChangeType()
- It allows you to use runtime information on any IConvertible
type to change representation formats. Not all conversions are possible, though, and you may need to write special case logic if you want to support conversions from types that are not IConvertible
.
The corresponding code (without exception handling or special case logic) would be:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
As several others have said, you want to use Convert.ChangeType
:
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
In fact, I recommend you look at the entire Convert
Class.
This class, and many other useful classes are part of the System
Namespace. I find it useful to scan that namespace every year or so to see what features I've missed. Give it a try!
I tried the answer from LBushkin and it worked great, but it won't work for null values and nullable fields. So I've changed it to this:
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);
}
I notice a lot of people are recommending Convert.ChangeType
- This does work for some cases however as soon as you start involving nullable
types you will start receiving InvalidCastExceptions
:
http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx
A wrapper was written a few years ago to handle this but that isn't perfect either.
http://weblogs.asp.net/pjohnson/archive/2006/02/07/Convert.ChangeType-doesn_2700_t-handle-nullables.aspx
You can use a type converter (no error checking):
Ship ship = new Ship();
string value = "5.5";
var property = ship.GetType().GetProperty("Latitude");
var convertedValue = property.Converter.ConvertFrom(value);
property.SetValue(self, convertedValue);
In terms of organizing the code, you could create a kind-of mixin that would result in code like this:
Ship ship = new Ship();
ship.SetPropertyAsString("Latitude", "5.5");
This would be achieved with this code:
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
can be reused for many different classes.
You can also create your own custom type converters to attach to your properties or classes:
public class Ship : MPropertyAsStringSettable {
public Latitude Latitude { get; set; }
// ...
}
[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }
You're probably looking for the Convert.ChangeType
method. For example:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Using Convert.ChangeType
and getting the type to convert from the PropertyInfo.PropertyType
.
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
I will answer this with a general answer. Usually these answers not working with guids. Here is a working version with guids too.
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);
Or you could try:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
If you are writing Metro app, you should use other code:
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType));
Note:
ship.GetType().GetTypeInfo().GetDeclaredProperty("Latitude");
instead of
ship.GetType().GetProperty("Latitude");
Using the following code should solve your issue:
item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With