我正在尝试制作模型反射工具。到目前为止我走了很长的路,但现在我被卡住了。
我有这个
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”并访问该对象的属性?
答案 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.