通过反射使用字符串值设置属性
-
23-08-2019 - |
题
我想通过反射设置对象的属性,其值为 type 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.String”类型的对象无法转换为“System.Double”类型。
如何根据以下内容将值转换为正确的类型 propertyInfo
?
解决方案
您可以使用 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);
其他提示
正如其他几个人所说,你想使用 Convert.ChangeType
:
propertyInfo.SetValue(ship,
Convert.ChangeType(value, propertyInfo.PropertyType),
null);
事实上,我建议你看整个 Convert
班级.
这个类和许多其他有用的类都是 System
命名空间. 。我发现每年左右扫描该名称空间以查看我错过了哪些功能很有用。试一试!
我发现很多人都在推荐 Convert.ChangeType
- 这对于某些情况确实有效,但是一旦您开始涉及 nullable
您将开始收到的类型 InvalidCastExceptions
:
几年前编写了一个包装器来处理这个问题,但这也并不完美。
您可以使用类型转换器(不进行错误检查):
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 { ... }
我尝试了来自的答案 布什金 它工作得很好,但它不适用于空值和可为空的字段。所以我把它改成了这样:
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);
}
您可能正在寻找 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
.
propertyInfo.SetValue( ship,
Convert.ChangeType( value, propertyInfo.PropertyType ),
null );
我将用一般性的答案来回答这个问题。通常这些答案不适用于指南。这里还有一个带有指南的工作版本。
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);
或者你可以尝试:
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
//But this will cause problems if your string value IsNullOrEmplty...
如果您正在编写 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");
使用以下代码应该可以解决您的问题:
item.SetProperty(prop.Name, Convert.ChangeType(item.GetProperty(prop.Name).ToString().Trim(), prop.PropertyType));
您想尝试一下 Reflection 还是想构建一个生产软件?我想问为什么你要使用反射来设置属性。
Double new_latitude;
Double.TryParse (value, out new_latitude);
ship.Latitude = new_latitude;