有没有办法使用反射在一个集合上迭代(最好通过foreach)?我正在使用反射迭代对象中的属性,当程序到达一个集合类型时,我希望它迭代集合的内容并能够访问集合中的对象。
目前,我在所有属性上都设置了属性,并且在集合属性上将IsCollection标志设置为true。我的代码检查此标志,如果是,则使用反射获取Type。有没有办法在某个集合上以某种方式调用GetEnumerator或Items才能迭代这些项?
答案 0 :(得分:35)
我有这个问题,但我最后只是检查它是否是IEnumerable而不是使用反射。所有集合都实现了这一点。
if (item is IEnumerable)
{
foreach (object o in (item as IEnumerable))
{
}
} else {
// reflect over item
}
答案 1 :(得分:29)
我尝试使用与Darren建议类似的技术,但请注意,不只是集合实现了IEnumerable。例如,string
也是IEnumerable,将迭代字符。
这是一个小函数我用来确定一个对象是否是一个集合(由于ICollection也是IEnumerable,它也是可枚举的。)
public bool isCollection(object o)
{
return typeof(ICollection).IsAssignableFrom(o.GetType())
|| typeof(ICollection<>).IsAssignableFrom(o.GetType());
}
答案 2 :(得分:8)
只需获取属性的值,然后将其转换为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
答案 3 :(得分:2)
你可能做的最好的事情就是检查对象是否实现了某些集合接口 - 可能IEnumerable就是你所需要的。然后,只需从对象调用GetEnumerator(),并使用IEnumerator.MoveNext()和IEnumerator.Current来处理集合。
如果集合没有实现这些接口,这对你没有帮助,但是如果是这样的话,那我认为它并不是一个集合。
答案 4 :(得分:2)
仅供参考,可能是某人的帮助...... 我有一个嵌套类的类和一些其他类的集合。我想保存类的属性值以及嵌套类和类集合。我的代码如下:
public void LogObject(object obj, int indent)
{
if (obj == null) return;
string indentString = new string(' ', indent);
Type objType = obj.GetType();
PropertyInfo[] properties = objType.GetProperties();
foreach (PropertyInfo property in properties)
{
Type tColl = typeof(ICollection<>);
Type t = property.PropertyType;
string name = property.Name;
object propValue = property.GetValue(obj, null);
//check for nested classes as properties
if (property.PropertyType.Assembly == objType.Assembly)
{
string _result = string.Format("{0}{1}:", indentString, property.Name);
log.Info(_result);
LogObject(propValue, indent + 2);
}
else
{
string _result = string.Format("{0}{1}: {2}", indentString, property.Name, propValue);
log.Info(_result);
}
//check for collection
if (t.IsGenericType && tColl.IsAssignableFrom(t.GetGenericTypeDefinition()) ||
t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == tColl))
{
//var get = property.GetGetMethod();
IEnumerable listObject = (IEnumerable)property.GetValue(obj, null);
if (listObject != null)
{
foreach (object o in listObject)
{
LogObject(o, indent + 2);
}
}
}
}
}
调用此函数
LogObject(obj, 0);
但是,我的课程中有一些结构,我需要弄清楚如何获取它们的值。 Moreoevr,我有一些好评。我也需要得到它们的价值......如果我更新我的代码,我会发布。
答案 5 :(得分:0)
使用反射时,您不一定使用该对象的实例。您必须创建一个能够遍历对象属性的该类型的实例。因此,如果使用反射,请使用ConstructorInfo.Invoke()(?)方法创建新实例或指向该类型的实例。
答案 6 :(得分:0)
一种相当简单的方法是将对象类型转换为集合并直接使用它。
答案 7 :(得分:0)
我会看一下Type.FindInterfaces方法。这可以过滤掉给定类型实现的接口。如在PropertyInfo.PropertyType.FindInterfaces(filterMethod,filterObjects)中。您可以按IEnumerable进行筛选,并查看是否返回任何结果。 MSDN在方法文档中有一个很好的例子。
答案 8 :(得分:0)
如果您没有使用对象的实例而是使用Type,则可以使用以下命令:
// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}