2011-11-11 40 views
5

Tôi đang cố gắng tạo một quy trình đệ quy sẽ truy lục PropertyInfos cho tất cả các thành viên theo một đối tượng được chỉ định (trong .NET 3.5). Tất cả mọi thứ cho các thành viên ngay lập tức đang làm việc, nhưng nó cũng cần phải phân tích các lớp lồng nhau (và các lớp lồng nhau của chúng, vv).Thường quy đệ quy để lấy PropertyInfo

Tôi không hiểu cách xử lý phần phân tích các lớp lồng nhau. Làm thế nào bạn sẽ viết phần này của mã?

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)); 
    } 

Edit: Tôi đã sử dụng một số gợi ý Harlam, và đã đưa ra một giải pháp làm việc. Điều này xử lý cả hai lớp lồng nhau và danh sách.

tôi đã thay thế vòng lặp trước đây của tôi qua PropertyInfo như sau

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); 
    } 
} 

Tôi cũng đã thêm một tấm séc mới để xem nếu một cái gì đó là một danh sách.

private static bool isList(Type type) 
{ 
    return 
     IsSubclassOfRawGeneric(type, typeof(List<>)); 
} 

Cảm ơn sự trợ giúp!

Trả lời

5

Tôi nghĩ điều này sẽ phù hợp với bạn. Ý tưởng ở đây là trả lại một đối tượng có thể đếm được từ mỗi cuộc gọi đến ProcessObject() và sau đó cuộn các cuộc gọi đó vào người gọi 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

Có thể sử dụng lợi tức lợi nhuận và cũng nên giữ một danh sách các đối tượng đã được xử lý cho thuộc tính tham chiếu trở lại. – riezebosch

+0

Điều này gần như hoạt động, nhưng nó đang gặp phải sự cố với danh sách. – Rethic

0

Hãy xem Devscribe. Nó là mã nguồn mở và sử dụng Reflection để lặp lại từng kiểu phản xạ - bao gồm việc xử lý Generics.