通过反射访问集合
有没有一种方法可以使用反射来迭代(最好是通过foreach)整个集合?我正在使用反射来遍历对象中的属性,当程序进入到一个集合类型时,我希望它可以遍历集合的内容并能够访问集合中的对象。
目前,我在所有属性上都设置了一个属性,并且在作为集合的属性上将IsCollection标志设置为true。我的代码检查此标志,如果为true,则使用反射获取Type。有没有办法以某种方式在集合上调用GetEnumerator或者Items以便能够遍历这些item?
解决方案
使用反射时,不一定要使用该对象的实例。我们将必须创建这种类型的实例,以能够遍历对象的属性。因此,如果我们使用反射,请使用ConstructorInfo.Invoke()(?)方法创建一个新实例或者指向该类型的实例。
我们可能最好的办法是检查对象是否实现了某些集合接口,而IEnumerable可能就是我们所需要的全部。然后,只需调用对象的GetEnumerator()并使用IEnumerator.MoveNext()和IEnumerator.Current即可遍历整个集合。
如果该集合没有实现这些接口,这将无济于事,但是我想,如果真是这样,那么它并不是真正的集合。
我遇到了这个问题,但是我没有使用反射,而只是检查它是否是IEnumerable。所有集合都实现了这一点。
if (item is IEnumerable) { foreach (object o in (item as IEnumerable)) { } } else { // reflect over item }
一个相当简单的方法是将对象类型转换为集合并直接使用它。
只需获取属性的值,然后将其转换为IEnumerable。以下是一些(未试用的)代码,可以使我们有所了解:
ClassWithListProperty obj = new ClassWithListProperty(); obj.List.Add(1); obj.List.Add(2); obj.List.Add(3); Type type = obj.GetType(); PropertyInfo listProperty = type.GetProperty("List", BindingFlags.Public); IEnumerable listObject = (IEnumerable) listProperty.GetValue(obj, null); foreach (int i in listObject) Console.Write(i); // should print out 123
我尝试使用与Darren建议的技术类似的技术,但是请注意,不仅仅是集合实现IEnumerable。例如," string"也是IEnumerable的,它将遍历字符。
这是一个小函数,用于确定对象是否为集合(由于ICollection也是IEnumerable,因此也可以枚举)。
public bool isCollection(object o) { return typeof(ICollection).IsAssignableFrom(o.GetType()) || typeof(ICollection<>).IsAssignableFrom(o.GetType()); }
我将看一下Type.FindInterfaces方法。这样可以过滤出由给定类型实现的接口。就像在PropertyInfo.PropertyType.FindInterfaces(filterMethod,filterObjects)中一样。我们可以按IEnumerable进行筛选,并查看是否返回任何结果。 MSDN在方法文档中有一个很好的例子。
如果我们不是使用对象的实例而是使用类型,则可以使用以下内容:
// type is IEnumerable if (type.GetInterface("IEnumerable") != null) { }