获取 PropertyInfo 的递归例程
Posted
技术标签:
【中文标题】获取 PropertyInfo 的递归例程【英文标题】:Recursive routine to obtain PropertyInfo 【发布时间】:2011-12-27 01:37:06 【问题描述】:我正在尝试创建一个递归例程,它将检索指定对象下所有成员的 PropertyInfos(在 .NET 3.5 中)。直接成员的一切都在工作,但它还需要解析嵌套类(以及它们的嵌套类等)。
我不明白如何处理解析嵌套类的部分。这部分代码你会怎么写?
public class ObjectWalkerEntity
public object Value get; set;
public PropertyInfo PropertyInfo get; set;
public static class ObjectWalker
// This will be the returned object
static List<ObjectWalkerEntity> objectList = new List<ObjectWalkerEntity>();
public static List<ObjectWalkerEntity> Walk(object o)
objectList.Clear();
processObject(o);
return objectList;
private static void processObject(object o)
if (o == null)
return;
Type t = o.GetType();
foreach (PropertyInfo pi in t.GetProperties())
if (isGeneric(pi.PropertyType))
// Add generic object
ObjectWalkerEntity obj = new ObjectWalkerEntity();
obj.PropertyInfo = pi;
obj.Value = pi.GetValue(o, null);
objectList.Add(obj);
else
////// TODO: Find a way to parse the members of the subclass...
// Parse each member of the non-generic object
foreach (Object item in pi.PropertyType)
processObject(item);
return;
private static bool isGeneric(Type type)
return
Extensions.IsSubclassOfRawGeneric(type, typeof(bool)) ||
Extensions.IsSubclassOfRawGeneric(type, typeof(string)) ||
Extensions.IsSubclassOfRawGeneric(type, typeof(int)) ||
Extensions.IsSubclassOfRawGeneric(type, typeof(UInt16)) ||
Extensions.IsSubclassOfRawGeneric(type, typeof(UInt32)) ||
Extensions.IsSubclassOfRawGeneric(type, typeof(UInt64)) ||
Extensions.IsSubclassOfRawGeneric(type, typeof(DateTime));
编辑:我采用了 Harlam 的一些建议,并提出了一个可行的解决方案。这处理嵌套类和列表。
我已经用以下内容替换了我之前通过 propertyinfo 的循环
foreach (PropertyInfo pi in t.GetProperties())
if (isGeneric(pi.PropertyType))
// Add generic object
ObjectWalkerEntity obj = new ObjectWalkerEntity();
obj.PropertyInfo = pi;
obj.Value = pi.GetValue(o, null);
objectList.Add(obj);
else if (isList(pi.PropertyType))
// Parse the list
var list = (IList)pi.GetValue(o, null);
foreach (object item in list)
processObject(item);
else
// Parse each member of the non-generic object
object value = pi.GetValue(o, null);
processObject(value);
我还添加了一项新检查,以查看某项是否为列表。
private static bool isList(Type type)
return
IsSubclassOfRawGeneric(type, typeof(List<>));
感谢您的帮助!
【问题讨论】:
【参考方案1】:看看Devscribe。它是开源的,使用 Reflection 来迭代每个反射类型——包括处理泛型。
【讨论】:
【参考方案2】:我认为这对你有用。这里的想法是从每次调用 ProcessObject()
返回一个可枚举对象,然后将这些调用汇总到调用者 List<ObjectWalkerEntity>
。
public class ObjectWalkerEntity
public object Value get; set;
public PropertyInfo PropertyInfo get; set;
public static class ObjectWalker
public static List<ObjectWalkerEntity> Walk(object o)
return ProcessObject(o).ToList();
private static IEnumerable<ObjectWalkerEntity> ProcessObject(object o)
if (o == null)
// nothing here, just return an empty enumerable object
return new ObjectWalkerEntity[0];
// create the list to hold values found in this object
var objectList = new List<ObjectWalkerEntity>();
Type t = o.GetType();
foreach (PropertyInfo pi in t.GetProperties())
if (IsGeneric(pi.PropertyType))
// Add generic object
var obj = new ObjectWalkerEntity();
obj.PropertyInfo = pi;
obj.Value = pi.GetValue(o, null);
objectList.Add(obj);
else
// not generic, get the property value and make the recursive call
object value = pi.GetValue(o, null);
// all values returned from the recursive call get
// rolled up into the list created in this call.
objectList.AddRange(ProcessObject(value));
return objectList.AsReadOnly();
private static bool IsGeneric(Type type)
return
IsSubclassOfRawGeneric(type, typeof(bool)) ||
IsSubclassOfRawGeneric(type, typeof(string)) ||
IsSubclassOfRawGeneric(type, typeof(int)) ||
IsSubclassOfRawGeneric(type, typeof(UInt16)) ||
IsSubclassOfRawGeneric(type, typeof(UInt32)) ||
IsSubclassOfRawGeneric(type, typeof(UInt64)) ||
IsSubclassOfRawGeneric(type, typeof(DateTime));
private static bool IsSubclassOfRawGeneric(Type generic, Type toCheck)
while (toCheck != typeof(object))
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur)
return true;
toCheck = toCheck.BaseType;
return false;
【讨论】:
可以使用 yield return 并且还应该保存一个已处理对象的列表以用于反向引用属性。 这几乎可以工作,但它遇到了列表问题。以上是关于获取 PropertyInfo 的递归例程的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法从该属性的 getter 中获取 PropertyInfo?
C#遍历类的属性 PropertyInfo.Attributes