反映清单<t> </t>

时间:2012-08-28 20:07:01

标签: c# generics reflection

我正在尝试制作模型反射工具。到目前为止我走了很长的路,但现在我被卡住了。

我有这个

public static void RenderModelList(List<T> modelList)
{
   foreach (T model in modelList)
   {
      PropertyInfo[] properties = model.GetType().GetProperties();
      foreach (PropertyInfo property in properties)
      {
         object propValue = property.GetValue(model, null);
         //Check if the property is a collection and do recursion 
         if (propValue != null)
         {
            if (isCollection(propValue))
            {   
               //This only works for Lists of the same <T> 
               List<T> li = Convert.ChangeType(propValue, propValue.GetType()) as List<T>;
               if (li != null)
               {
                  if (li.Count > 0)
                  {
                     RenderModelList(li, loop);
                  }                                            
               }
               else
               {
                  //Its another type what to do?
                  // Create a List<> of unknown type??         
               }
            }
         }
      }
   }
}

我的问题是,如果我传递此方法List<Persons>并且Person具有属性List<Cars> - 我不能使用Convert.ChangeType - 因为这不是T. / p>

那么如何循环“List”并访问该对象的属性?

2 个答案:

答案 0 :(得分:4)

在我看来,你的方法可以更松散地输入:

public static void RenderModelList(IEnumerable list)
{
    foreach (object model in list)
    {
        ...
    }
}

然后你只需要转换为IEnumerable,而不是特定的序列或列表类型。

答案 1 :(得分:3)

嗯,你的方法不应该依赖T。您可以改为使用IEnumerable(而不是IEnumerable<T>,因为它又取决于T)。请注意,每个List<T>都会实现IEnumerable,因此您的方法可以使用它们;但是,其他集合通常也会实现IEnumerable。这可能是您需要的也可能不是。

如果您选择提议的方式,那么您的测试isCollection将是这样的:

IEnumerable propValueAsEnumerable = propValue as IEnumerable;
if (propValueAsEnumerable != null)
    RenderModelList(propValueAsEnumerable);

我可能会将你的方法重构成类似的东西:

IEnumerable<object> GetPropertyValuesFlat(object o)
{
    return o.GetType()
            .GetProperties()
            .Select(pi => pi.GetValue(o, null))
            .Where(pv => pv != null)
            .SelectMany(pv => pv is IEnumerable<object> ?
                          (IEnumerable<object>)pv : new[] {pv});
}

//...
foreach (object p in GetPropertyValuesFlat(o))
    render(p);

(警告:未经测试)

编辑:嗯,无法正常工作,因为SelectMany无法理解非通用IEnumerable。将其更改为与IEnumerable<object>一起使用。至少,每个IEnumerable<T>都是IEnumerable<object>,类别为T.