简体   繁体   English

通过反思访问集合

[英]Accessing a Collection Through Reflection

Is there a way to iterate (through foreach preferably) over a collection using reflection? 有没有办法使用反射迭代(通过foreach优先)集合? I'm iterating over the properties in an object using reflection, and when the program gets to a type that is a collection, I'd like it to iterate over the contents of the collection and be able to access the objects in the collection. 我正在使用反射迭代对象中的属性,当程序到达一个集合类型时,我希望它迭代集合的内容并能够访问集合中的对象。

At the moment I have an attribute set on all of my properties, with an IsCollection flag set to true on the properties that are collections. 目前,我在所有属性上都设置了属性,并且在集合属性上将IsCollection标志设置为true。 My code checks for this flag and if it's true, it gets the Type using reflection. 我的代码检查此标志,如果是,则使用反射获取Type。 Is there a way to invoke GetEnumerator or Items somehow on a collection to be able to iterate over the items? 有没有办法在某个集合上以某种方式调用GetEnumerator或Items才能迭代这些项目?

I had this issue, but instead of using reflection, i ended up just checking if it was IEnumerable. 我有这个问题,但我没有使用反射,而是直接检查它是否是IEnumerable。 All collections implement that. 所有的集合都实现了

if (item is IEnumerable)
{
    foreach (object o in (item as IEnumerable))
    {

    }
} else {
   // reflect over item
}

I've tried to use a similar technique as Darren suggested, however just beware that not just collections implement IEnumerable. 我尝试使用与Darren建议类似的技术,但请注意,不只是集合实现了IEnumerable。 string for instance is also IEnumerable and will iterate over the characters. 例如, string也是IEnumerable并将迭代字符。

Here's a small function I'm using to determine if an object is a collection (which will be enumerable as well since ICollection is also IEnumerable). 这是一个小函数,我用来确定一个对象是否是一个集合(由于ICollection也是IEnumerable,它也是可枚举的)。

    public bool isCollection(object o)
    {
        return typeof(ICollection).IsAssignableFrom(o.GetType())
            || typeof(ICollection<>).IsAssignableFrom(o.GetType());
    }

Just get the value of the property and then cast it into an IEnumerable. 只需获取属性的值,然后将其转换为IEnumerable。 Here is some (untested) code to give you an idea: 这里有一些(未经测试的)代码可以给你一个想法:

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

The best you could probably do would be to check if the object implements certain collection interfaces - probably IEnumerable would be all that you need. 你可能做的最好的事情是检查对象是否实现了某些集合接口 - 可能IEnumerable就是你所需要的。 Then it's just a matter of calling GetEnumerator() off of the object, and using IEnumerator.MoveNext() and IEnumerator.Current to work your way through the collection. 然后,只需从对象调用GetEnumerator(),并使用IEnumerator.MoveNext()和IEnumerator.Current来处理集合。

This won't help you if the collection doesn't implement those interfaces, but if that's the case it's not really much of a collection, I suppose. 如果集合没有实现这些接口,这对你没有帮助,但是如果是这样的话,我认为它并不是真正的集合。

Just for information may be it will be of someone's help... I had a class with nested classes and collection of some other classes. 只是为了获取信息可能是某人的帮助......我有一个有嵌套类的类和一些其他类的集合。 I wanted to save the property values of the class as well nested classes and collection of classes. 我想保存类的属性值以及嵌套类和类集合。 My code is as follows: 我的代码如下:

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

An called this function 一个叫这个函数

LogObject(obj, 0);

However, I have some structs inside my classes and I need to figure out how to get their values. 但是,我的课程中有一些结构,我需要弄清楚如何获得它们的值。 Moreoevr, I have some LIst. Moreoevr,我有一些好评。 I need to get their value as well.... I will post if I update my code. 我也需要获得它们的价值......如果我更新我的代码,我会发布。

When your using reflection you aren't necessarily using an instance of that object. 使用反射时,您不一定使用该对象的实例。 You would have to create an instance of that type of be able to iterate through the object's properties. 您必须创建一个能够遍历对象属性的该类型的实例。 So if you are using reflection use the ConstructorInfo.Invoke() (?) method to create a new instance or point to an instance of the type. 因此,如果使用反射,请使用ConstructorInfo.Invoke()(?)方法创建新实例或指向该类型的实例。

一种相当简单的方法是将对象类型转换为集合并直接使用它。

If you're not using an instance of the object but rather a Type, you can use the following: 如果您没有使用对象的实例而是使用Type,则可以使用以下命令:

// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}

I would look at the Type.FindInterfaces method. 我会看一下Type.FindInterfaces方法。 This can filter out the interfaces implemented by a given type. 这可以过滤掉给定类型实现的接口。 As in PropertyInfo.PropertyType.FindInterfaces(filterMethod, filterObjects). 如在PropertyInfo.PropertyType.FindInterfaces(filterMethod,filterObjects)中。 You can filter by IEnumerable and see if any results are returned. 您可以按IEnumerable进行筛选,并查看是否返回任何结果。 MSDN has a great example in the method documentation. MSDN在方法文档中有一个很好的例子。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM