C# 获取PropertyInfo的递归例程

C# 获取PropertyInfo的递归例程,c#,reflection,.net-3.5,recursion,C#,Reflection,.net 3.5,Recursion,我正在尝试创建一个递归例程,该例程将检索指定对象(在.NET 3.5中)下所有成员的PropertyInfo。直接成员的一切工作正常,但它也需要解析嵌套类(及其嵌套类等) 我不明白如何处理解析嵌套类的部分。您将如何编写这部分代码 public class ObjectWalkerEntity { public object Value { get; set; } public PropertyInfo PropertyInfo { get; set; } } public s

我正在尝试创建一个递归例程,该例程将检索指定对象(在.NET 3.5中)下所有成员的PropertyInfo。直接成员的一切工作正常,但它也需要解析嵌套类(及其嵌套类等)

我不明白如何处理解析嵌套类的部分。您将如何编写这部分代码

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));
    }
我还添加了一个新的检查,以查看某个内容是否是列表

private static bool isList(Type type)
{
    return
        IsSubclassOfRawGeneric(type, typeof(List<>));
}
private static bool isList(类型)
{
返回
IsSubclassOfRawGeneric(类型、类型(列表));
}

谢谢你的帮助

我想这对你有用。这里的想法是从对
ProcessObject()
的每次调用中返回一个可枚举对象,然后将这些调用上卷到调用者
列表中

公共类ObjectWalkerEntity
{
公共对象值{get;set;}
公共属性信息属性信息{get;set;}
}
公共静态类ObjectWalker
{
公共静态列表漫游(对象o)
{
返回ProcessObject(o.ToList();
}
私有静态IEnumerable ProcessObject(对象o)
{
如果(o==null)
{
//这里什么都没有,只返回一个空的可枚举对象
返回新的ObjectWalkerEntity[0];
}
//创建列表以保存在此对象中找到的值
var objectList=新列表();
类型t=o.GetType();
foreach(t.GetProperties()中的PropertyInfo pi)
{
if(IsGeneric(pi.PropertyType))
{
//添加泛型对象
var obj=new ObjectWalkerEntity();
obj.PropertyInfo=pi;
obj.Value=pi.GetValue(o,null);
objectList.Add(obj);
}
其他的
{
//非泛型,获取属性值并进行递归调用
对象值=pi.GetValue(o,null);
//从递归调用返回的所有值
//上卷到此调用中创建的列表中。
AddRange(ProcessObject(value));
}
} 
返回objectList.AsReadOnly();
}
私有静态bool为泛型(类型)
{
返回
IsSubclassOfRawGeneric(类型,类型(bool))||
IsSubclassOfRawGeneric(类型、类型(字符串))||
IsSubclassOfRawGeneric(类型,类型(int))||
IsSubclassOfRawGeneric(类型,类型(UInt16))||
IsSubclassOfRawGeneric(类型,类型(UInt32))||
IsSubclassOfRawGeneric(类型,类型(UInt64))||
IsSubclassOfRawGeneric(类型,类型(日期时间));
}
私有静态bool IsSubclassOfRawGeneric(类型generic,类型toCheck)
{
while(toCheck!=typeof(对象))
{
var cur=toCheck.IsGenericType?toCheck.GetGenericTypeDefinition():toCheck;
如果(通用==cur)
{
返回true;
}
toCheck=toCheck.BaseType;
}
返回false;
}
}

看一看。它是开源的,使用反射来迭代每种反射类型,包括处理泛型。

可以使用yield-return,还应该为back-reference属性保存一个已处理对象的列表。这几乎可以工作,但它遇到了列表问题。
private static bool isList(Type type)
{
    return
        IsSubclassOfRawGeneric(type, typeof(List<>));
}
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;
   }
}