使用字符串值通过反射设置属性

我想通过反射设置一个对象的属性,值类型为string。 因此,例如,假设我有一个Ship类,其属性为Latitude,这是一个double.

这是我想做的:

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

就像这样,这会抛出ArgumentException:

类型为System的对象。字符串'不能转换为'System.Double'类型。

如何将值转换为适当的类型,基于propertyInfo?

327709 次浏览

正如其他人所说,你想要使用Convert.ChangeType:

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

事实上,我建议你看一下整个Convert

这个类和许多其他有用的类都是System名称空间的一部分。我发现,大约每隔一年扫描一下这个名称空间,看看我遗漏了哪些特性,这很有用。试试吧!

你可以使用Convert.ChangeType()——它允许你在任何IConvertible类型上使用运行时信息来改变表示格式。然而,并不是所有的转换都是可能的,如果你想支持从非IConvertible类型的转换,你可能需要编写特殊情况的逻辑。

相应的代码(没有异常处理或特殊情况逻辑)将是:

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

或者你可以试试:

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


//But this will cause problems if your string value IsNullOrEmplty...

你可能正在寻找Convert.ChangeType方法。例如:

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

使用Convert.ChangeType并获取要从PropertyInfo.PropertyType. xml转换的类型。

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

您是想玩玩Reflection还是想构建一个软件产品?我想问你为什么要用反射来设置属性。

Double new_latitude;


Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;

我注意到很多人都推荐Convert.ChangeType -这在某些情况下确实有效,但是一旦你开始涉及nullable类型,你就会开始收到InvalidCastExceptions:

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

几年前编写了一个包装器来处理这个问题,但这也不是完美的。

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

你可以使用类型转换器(没有错误检查):

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

在组织代码方面,你可以创建一个一种混合,结果是这样的代码:

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

这将通过以下代码实现:

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可以被许多不同的类重用。

你也可以创建你自己的自定义类型转换器来附加到你的属性或类:

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


[TypeConverter(typeof(LatitudeConverter))]
public class Latitude { ... }

如果你正在编写Metro应用程序,你应该使用其他代码:

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

注意:

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

而不是

ship.GetType().GetProperty("Latitude");

我尝试了LBushkin的答案,它工作得很好,但它不适用于空值和可空字段。所以我把它改成这样:

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

我将用一个一般的答案来回答这个问题。通常这些答案不工作与指导。这是一个工作版本与guids。

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

使用下面的代码可以解决你的问题:

item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));