我需要使用反射来设置类的属性。
我有一个Dictionary<string,string>
,其中包含属性名称和字符串值。
在反射循环中,我需要在为每个属性设置值时将字符串值转换为适当的属性类型。其中一些属性类型是可空类型。
修改 在这个博客的评论中定义的第一个方法似乎也是这样做的: http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx
答案 0 :(得分:13)
执行此操作的一种方法是:
type.GetGenericTypeDefinition() == typeof(Nullable<>)
只需设置为任何其他反射代码:
propertyInfo.SetValue(yourObject, yourValue);
答案 1 :(得分:13)
为什么你需要知道它是否可以为空?你的意思是“引用类型”,或“Nullable<T>
”?
无论哪种方式,使用字符串值,最简单的选项是通过TypeConverter
PropertyDescriptor
,PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
// then per property...
PropertyDescriptor prop = props[propName];
prop.SetValue(obj, prop.Converter.ConvertFromInvariantString(value));
更容易(更准确)地提供:
{{1}}
这应该使用正确的转换器,即使设置per-property(而不是per-type)。最后,如果您正在执行大量此操作,则可以通过HyperDescriptor
进行加速,而无需更改代码(除了为类型启用它之外,仅执行一次)。
答案 2 :(得分:6)
特别是将整数转换为枚举并分配给可以为空的枚举属性:
int value = 4;
if(propertyInfo.PropertyType.IsGenericType
&& Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null
&& Nullable.GetUnderlyingType(propertyInfo.PropertyType).IsEnum)
{
var enumType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
var enumValue = Enum.ToObject(enumType, value);
propertyInfo.SetValue(item, enumValue, null);
//-- suggest by valamas
//propertyInfo.SetValue(item, (value == null ? null : enumValue), null);
}
答案 3 :(得分:3)
我创建了小样本。如果您对此代码有任何疑问,请添加评论。
编辑:根据Marc Gravell的精彩评论更新样本
class Program
{
public int? NullableProperty { get; set; }
static void Main(string[] args)
{
var value = "123";
var program = new Program();
var property = typeof(Program).GetProperty("NullableProperty");
var propertyDescriptors = TypeDescriptor.GetProperties(typeof(Program));
var propertyDescriptor = propertyDescriptors.Find("NullableProperty", false);
var underlyingType =
Nullable.GetUnderlyingType(propertyDescriptor.PropertyType);
if (underlyingType != null)
{
var converter = propertyDescriptor.Converter;
if (converter != null && converter.CanConvertFrom(typeof(string)))
{
var convertedValue = converter.ConvertFrom(value);
property.SetValue(program, convertedValue, null);
Console.WriteLine(program.NullableProperty);
}
}
}
}
答案 4 :(得分:1)
最初,MSDN forum提到了最佳解决方案。但是,当您需要实现动态解决方案时,您不确切地知道可以在类上声明多少可空字段,最好的办法是检查Nullable&lt;&gt;类型可以分配给 属性,通过反射检查
protected T initializeMe<T>(T entity, Value value)
{
Type eType = entity.GetType();
foreach (PropertyInfo pi in eType.GetProperties())
{
//get and nsame of the column in DataRow
Type valueType = pi.GetType();
if (value != System.DBNull.Value )
{
pi.SetValue(entity, value, null);
}
else if (valueType.IsGenericType && typeof(Nullable<>).IsAssignableFrom(valueType)) //checking if nullable can be assigned to proptety
{
pi.SetValue(entity, null, null);
}
else
{
System.Diagnostics.Trace.WriteLine("something here");
}
...
}
...
}
答案 5 :(得分:1)
我使用了以下解决方案,避免使用类型转换器来更好地控制代码。
我写了一个辅助类来支持操作
Sub Rowcount()
'Charles, M
Dim H As Long
Set sh = Worksheets("Report-Charles, M")
H = sh.UsedRange.Rows.Count
Range("I2:I" & H).Formula = "=IF((AND(OR(E2=""Unrated"",E2=""""),OR(G2<>""Unrated"",G2<>""""))),G2,IF(E2>=""4,25"",""High Performance"",IF(E2<""3,35"",""Low Performance"",IF(AND(E2>=""3,35"",E2<""4,25""),""Medium Performance"",""Unrated""))))"
MsgBox (H) & "Rows have been Autofilled with 3 scale Rating Results"
End Sub
注意:当你设置一个可以为空的值(例如int?)时,该值几乎必须是整数或可转换类型。你不能在一个字节上设置int?所以,你需要正确转换。请参阅ConvertValue()代码,它检查type(int)和相应的可空类型(int?))
这是使用所需数据结构设置值的代码,字典。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
public static class ObjectExtensions
{
/// <summary>
/// Enable using reflection for setting property value
/// on every object giving property name and value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="target"></param>
/// <param name="propertyName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool SetProperty<T>(this T target, string propertyName, object value)
{
PropertyInfo pi = target.GetType().GetProperty(propertyName);
if (pi == null)
{
Debug.Assert(false);
return false;
}
try
{
// Convert the value to set to the properly type
value = ConvertValue(pi.PropertyType, value);
// Set the value with the correct type
pi.SetValue(target, value, null);
}
catch (Exception ex)
{
Debug.Assert(false);
return false;
}
return true;
}
private static object ConvertValue(Type propertyType, object value)
{
// Check each type You need to handle
// In this way You have control on conversion operation, before assigning value
if (propertyType == typeof(int) ||
propertyType == typeof(int?))
{
int intValue;
if (int.TryParse(value.ToString(), out intValue))
value = intValue;
}
else if (propertyType == typeof(byte) ||
propertyType == typeof(byte?))
{
byte byteValue;
if (byte.TryParse(value.ToString(), out byteValue))
value = byteValue;
}
else if (propertyType == typeof(string))
{
value = value.ToString();
}
else
{
// Extend Your own handled types
Debug.Assert(false);
}
return value;
}
}
答案 6 :(得分:0)
检查Nullable类型很容易,int?实际上是System.Nullable<System.Int32>
。
因此,您只需检查类型是否为System.Nullable<T>
的通用实例。
设置不应有所作为,nullableProperty.SetValue(instance, null)
或nullableProperty.SetValue(instance, 3)
答案 7 :(得分:0)
这是&#34; nullable&#34;最安全的解决方案。对象类型
if (reader[rName] != DBNull.Value)
{
PropertyInfo pi = (PropertyInfo)d[rName.ToLower()];
if (pi.PropertyType.FullName.ToLower().Contains("nullable"))
pi.SetValue(item, reader[rName]);
else
pi.SetValue(item, Convert.ChangeType(reader[rName], Type.GetType(pi.PropertyType.FullName)), null);
}