32

リフレクションを使用してコレクションを (できれば foreach を介して) 反復処理する方法はありますか? リフレクションを使用してオブジェクトのプロパティを反復処理しています。プログラムがコレクションである型に到達したら、コレクションの内容を反復処理して、コレクション内のオブジェクトにアクセスできるようにしたいと考えています。

現時点では、コレクションであるプロパティで IsCollection フラグを true に設定して、すべてのプロパティに属性を設定しています。私のコードはこのフラグをチェックし、それが true の場合、リフレクションを使用して Type を取得します。コレクションでGetEnumeratorまたはItemsを何らかの方法で呼び出して、アイテムを反復処理できるようにする方法はありますか?

4

9 に答える 9

36

私はこの問題を抱えていましたが、リフレクションを使用する代わりに、それが IEnumerable かどうかを確認するだけになりました。すべてのコレクションがそれを実装しています。

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

    }
} else {
   // reflect over item
}
于 2008-09-19T19:12:19.263 に答える
31

ダレンが提案したのと同様の手法を使用しようとしましたが、コレクションだけが IEnumerable を実装していないことに注意してください。stringたとえば、IEnumerable でもあり、文字を反復処理します。

これは、オブジェクトがコレクションであるかどうかを判断するために使用している小さな関数です (ICollection も IEnumerable であるため、列挙可能になります)。

    public bool isCollection(object o)
    {
        return typeof(ICollection).IsAssignableFrom(o.GetType())
            || typeof(ICollection<>).IsAssignableFrom(o.GetType());
    }
于 2009-02-14T15:06:43.900 に答える
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
于 2008-09-19T19:22:24.030 に答える
3

参考までに、誰かの助けになるかもしれません...ネストされたクラスと他のクラスのコレクションを持つクラスがありました。クラスのプロパティ値、ネストされたクラス、およびクラスのコレクションを保存したかったのです。私のコードは次のとおりです。

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

ただし、クラス内にいくつかの構造体があり、それらの値を取得する方法を理解する必要があります。さらに、私はいくつかのリストを持っています。それらの値も取得する必要があります....コードを更新したら投稿します。

于 2012-05-23T19:16:39.143 に答える
2

おそらく最善の方法は、オブジェクトが特定のコレクションインターフェイスを実装しているかどうかを確認することです。おそらく、必要なのはIEnumerableだけです。次に、オブジェクトからGetEnumerator()を呼び出し、IEnumerator.MoveNext()とIEnumerator.Currentを使用してコレクションを処理します。

コレクションがこれらのインターフェイスを実装していない場合、これは役に立ちませんが、その場合は、コレクションの多くではないと思います。

于 2008-09-19T19:11:48.597 に答える
0

リフレクションを使用する場合、必ずしもそのオブジェクトのインスタンスを使用しているとは限りません。オブジェクトのプロパティを反復処理できるそのタイプのインスタンスを作成する必要があります。したがって、リフレクションを使用している場合は、ConstructorInfo.Invoke()(?)メソッドを使用して、新しいインスタンスを作成するか、タイプのインスタンスをポイントします。

于 2008-09-19T19:11:35.460 に答える
0

かなり単純なアプローチは、オブジェクトをコレクションとして型キャストし、それを直接使用することです。

于 2008-09-19T19:14:15.297 に答える
0

オブジェクトのインスタンスではなくタイプを使用している場合は、次を使用できます。

// type is IEnumerable
if (type.GetInterface("IEnumerable") != null)
{
}
于 2010-06-10T07:37:09.640 に答える