获取 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&lt;ObjectWalkerEntity&gt;

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类获取数据的DbType值

反思:如何通过PropertyInfo获取类对象

C#遍历类的属性 PropertyInfo.Attributes

我可以在不使用反射的情况下获取类中字段或属性的 PropertyInfo 吗?

EF 获取类的属性并排除特定属性(getType().GetProperties())