public class Address
{
public string ZipCode {get; set;}
}
public class Customer
{
public Address Address {get; set;}
}
如何使用反射访问"ZipCode"或"Address.ZipCode"? 例如:
Typeof(Customer).GetProperty("ZipCode")?
public class Address
{
public string ZipCode {get; set;}
}
public class Customer
{
public Address Address {get; set;}
}
如何使用反射访问"ZipCode"或"Address.ZipCode"? 例如:
Typeof(Customer).GetProperty("ZipCode")?
你需要类似这样的东西:
PropertyInfo addressProperty = typeof(Customer).GetProperty("Address");
ProportyInfo zipCodeProperty = addressProperty.PropertyType.GetProperty("ZipCode");
object address = addressProperty.GetValue(customer, null);
object zipCode = zipCodeProperty.GetValue(address, null);
基本上,如果你想要获取字符串 "Address.ZipCode" 并向下遍历它,你需要通过 "." 进行分割,然后在每一步调用适当类型的 GetProperty 方法来获取属性本身,接着使用 PropertyInfo.GetValue 方法来获取链中的下一个值。可以像这样:
public static object FollowPropertyPath(object value, string path)
{
Type currentType = value.GetType();
foreach (string propertyName in path.Split('.'))
{
PropertyInfo property = currentType.GetProperty(propertyName);
value = property.GetValue(value, null);
currentType = property.PropertyType;
}
return value;
}
这样调用:
object zipCode = FollowPropertyPath(customer, "Address.ZipCode");
请注意,此方法适用于属性的编译时类型。如果您希望它适应执行时类型(例如,如果customer.Address没有ZipCode属性,但是Address返回的实际类型有),则将property.PropertyType
更改为property.GetType()
。
还要注意,此方法不具备任何错误处理等功能 :)
Jon Skeet的回答很好,但是我还需要稍作修改来考虑属性路径中的派生实例:
public static class ReflectorUtil
{
public static object FollowPropertyPath(object value, string path)
{
if (value == null) throw new ArgumentNullException("value");
if (path == null) throw new ArgumentNullException("path");
Type currentType = value.GetType();
object obj = value;
foreach (string propertyName in path.Split('.'))
{
if (currentType != null)
{
PropertyInfo property = null;
int brackStart = propertyName.IndexOf("[");
int brackEnd = propertyName.IndexOf("]");
property = currentType.GetProperty(brackStart > 0 ? propertyName.Substring(0, brackStart) : propertyName);
obj = property.GetValue(obj, null);
if (brackStart > 0)
{
string index = propertyName.Substring(brackStart + 1, brackEnd - brackStart - 1);
foreach (Type iType in obj.GetType().GetInterfaces())
{
if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IDictionary<,>))
{
obj = typeof(ReflectorUtil).GetMethod("GetDictionaryElement")
.MakeGenericMethod(iType.GetGenericArguments())
.Invoke(null, new object[] { obj, index });
break;
}
if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IList<>))
{
obj = typeof(ReflectorUtil).GetMethod("GetListElement")
.MakeGenericMethod(iType.GetGenericArguments())
.Invoke(null, new object[] { obj, index });
break;
}
}
}
currentType = obj != null ? obj.GetType() : null; //property.PropertyType;
}
else return null;
}
return obj;
}
public static TValue GetDictionaryElement<TKey, TValue>(IDictionary<TKey, TValue> dict, object index)
{
TKey key = (TKey)Convert.ChangeType(index, typeof(TKey), null);
return dict[key];
}
public static T GetListElement<T>(IList<T> list, object index)
{
return list[Convert.ToInt32(index)];
}
}
static void Main()
{
object obj = new Customer { Address = new Address { ZipCode = "abcdef" } };
object address = GetValue(obj, "Address");
object zip = GetValue(address, "ZipCode");
Console.WriteLine(zip);
}
static object GetValue(object component, string propertyName)
{
return TypeDescriptor.GetProperties(component)[propertyName].GetValue(component);
}
这样做会使你具有与数据绑定到"Address.ZipCode"相同的处理能力(忽略一些细节,如列表等)。
(请注意,如果您知道预期类型,可以将zip转换为字符串等)
要从深层路径(包括数据绑定使用的相同列表处理)获取值,您可以使用类似于以下内容:
static object ResolveValue(object component, string path) {
foreach(string segment in path.Split('.')) {
if (component == null) return null;
if(component is IListSource) {
component = ((IListSource)component).GetList();
}
if (component is IList) {
component = ((IList)component)[0];
}
component = GetValue(component, segment);
}
return component;
}
这个列表的东西 大致 类似于常规数据绑定的行为(尽管它省略了一些像绑定上下文、货币管理器等的内容)
typeof (Customer).GetProperty("Address").PropertyType.GetProperty("ZipCode")
currentType = property.PropertyType
仅返回System.Object,并在foreach循环的下一次迭代中失败。public static object FollowPropertyPath(object value, string path)
{
Type currentType = value.GetType();
foreach (string propertyName in path.Split('.'))
{
PropertyInfo property = currentType.GetProperty(propertyName);
value = property.GetValue(value, null);
currentType = value.GetType(); // <-- Change
}
return value;
}
adabyron,
我为你的代码创建了一个版本,当你只需要获取类型时使用,如果你没有实际的对象实例。
public static Type FollowPropertyPath<T>(string path)
{
if (path == null) throw new ArgumentNullException("path");
Type currentType = typeof(T);
foreach (string propertyName in path.Split('.'))
{
int brackStart = propertyName.IndexOf("[");
var property = currentType.GetProperty(brackStart > 0 ? propertyName.Substring(0, brackStart) : propertyName);
if (property == null)
return null;
currentType = property.PropertyType;
if (brackStart > 0)
{
foreach (Type iType in currentType.GetInterfaces())
{
if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof (IDictionary<,>))
{
currentType = iType.GetGenericArguments()[1];
break;
}
if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof (ICollection<>))
{
currentType = iType.GetGenericArguments()[0];
break;
}
}
}
}
return currentType;
}
somePerson.Adresses[3].Street
)上失败。 - Oliver