2011-11-11 81 views
5

我試圖創建一個遞歸例程,它將爲指定對象(在.NET 3.5中)下的所有成員檢索PropertyInfos。直接成員的所有東西都在工作,但它也需要解析嵌套類(以及它們的嵌套類等)。遞歸例程獲取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)); 
    } 

編輯:我已經使用了一些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<>)); 
} 

感謝您的幫助!

回答

5

我認爲這會對你有用。這裏的想法是將來自每個呼叫的可枚舉對象返回到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; 
    } 
} 
+0

可以使用收益率回報,並且還應該包含一個已經處理過的對象列表,用於反向引用屬性。 – riezebosch

+0

這幾乎可以工作,但遇到列表問題。 – Rethic

0

看看Devscribe。它是開源的,使用Reflection來迭代每個反射類型 - 包括處理泛型。