2010-11-24 10 views
8

私は反射のみ経由へのアクセス権を持っているインデックス付きプロパティをオーバーitterateしたい、、(リフレクション)

が、インデックス付きプロパティを反復処理(と私はおそらく、あきれるほど単純な答えがあることを完全な知識でこれを言いますMSDN/Google fail = /)TargetInvocationExceptionがスローされるまで、PropertyInfo.GetValue(prop, counter)以上のカウンターをインクリメントする以外に方法を見つける/考えられません。

ALA:

foreach (PropertyInfo prop in obj.GetType().GetProperties()) 
{ 
    if (prop.GetIndexParameters().Length > 0) 
    { 
     // get an integer count value, by incrementing a counter until the exception is thrown 
     int count = 0; 
     while (true) 
     { 
      try 
      { 
       prop.GetValue(obj, new object[] { count }); 
       count++; 
      } 
      catch (TargetInvocationException) { break; } 
     } 

     for (int i = 0; i < count; i++) 
     { 
      // process the items value 
      process(prop.GetValue(obj, new object[] { i })); 
     } 
    } 
} 

今、いくつかの問題が..この...非常に醜い..溶液である

それは多次元または、例えば、整数で索引付けされていない何場合

..

私が試してみて誰かがそれを必要とするなら、それを働かせるために使っているテストコードです。興味があれば私はカスタムキャッシュシステムを作っていて、.Equalsはそれをカットしません。

static void Main() 
    { 
     object str = new String(("Hello, World").ToArray()); 

     process(str); 

     Console.ReadKey(); 
    } 

    static void process(object obj) 
    { 
     Type type = obj.GetType(); 

     PropertyInfo[] properties = type.GetProperties(); 

     // if this obj has sub properties, apply this process to those rather than this. 
     if (properties.Length > 0) 
     { 
      foreach (PropertyInfo prop in properties) 
      { 
       // if it's an indexed type, run for each 
       if (prop.GetIndexParameters().Length > 0) 
       { 
        // get an integer count value 
        // issues, what if it's not an integer index (Dictionary?), what if it's multi-dimensional? 
        // just need to be able to iterate through each value in the indexed property 
        int count = 0; 
        while (true) 
        { 
         try 
         { 
          prop.GetValue(obj, new object[] { count }); 
          count++; 
         } 
         catch (TargetInvocationException) { break; } 
        } 

        for (int i = 0; i < count; i++) 
        { 
         process(prop.GetValue(obj, new object[] { i })); 
        } 
       } 
       else 
       { 
        // is normal type so. 
        process(prop.GetValue(obj, null)); 
       } 
      } 
     } 
     else 
     { 
      // process to be applied to each property 
      Console.WriteLine("Property Value: {0}", obj.ToString()); 
     } 
    } 
+0

(( "こんにちは、世界")。てToArray())'? –

+0

単なる一例変数が...私の関数に渡す文字列/文字列を定義するさまざまな方法を試したと '...厄介な1のビットの上に残されたオブジェクトSTR =「こんにちは、世界!」;'ちょうど同様に働く。 –

+0

整数ではなくSTRINGキーがある場合はどうすればいいですか?私は彼らの名前を知らない。それらを見つけて使用するには? – Alexander

答えて

8

インデクサーのゲッターは、丸い角かっこを使用する点を除いて、通常の方法と同じです。メソッドの許容値の範囲を自動的に決定できるとは予想されないため、インデクサーにとっては実現不可能です。

+0

問題を回避するには、 '' Length'又はCount'呼ばれるメンバプロパティを検索し、整数インデックス特性については、UpperBound、または文字列インデックスプロパティの 'Keys'というプロパティとしてそれを使用するためにリフレクションを使用することです。 – Dai

2

PropertyInfo.GetIndexParametersを使用して、インデックス付きプロパティパラメータの数と種類を調べることができます。

あなたが「不正行為をしない」、そのプロパティが持つ内部情報を使用しない限り、これらのパラメータの「正当な」値が何であるかを見つけるためにできることは何もないと思います。

3

索引付けされたプロパティで順次インデックス番号を持つことは、何も賭けることができません。
インデックスされたプロパティは配列ではありません。
カウンターの例:あなたは通常この場合dictionary.Keysには、可能なインデックス値を取得するための他の方法を持っている種類に応じて

Dictionary<int, bool> dictionary = new Dictionary<int, bool>(); 
dictionary[1] = true; 
dictionary[5] = false; 

。あなたのタイプで可能ならこの順番で試してみてください

  1. タイプ自体にはIEnumerable<T>を実装してください。
  2. インデックス付きプロパティが複数ある場合は、インデックス付きプロパティごとに対応するIEnumerable<T>プロパティを実装できます。

有効な値が指定されておらず、有効な値が何であるかを尋ねる方法がない場合、あなたはほとんど運がありません。

+0

残念ながら、私は実行時まで(実際にはオブジェクト拡張メソッドとして実装されています)入力型を嫌に思っていますが、IEnumerable実装を検索するというアイディアを教えてくれました。感謝 –

4

インデクサーはメソッドにコンパイルされます。次に例を示します。

class IndexedData 
{ 
    public double this[int index] 
    { 
     get { return (double)index; } 
    } 
} 

このような何かにコンパイルされます:クラスの2つのdouble get_Item(int)方法があるので、次のコードをコンパイルすることはできません

public double get_Item(int index) 
{ 
    return (double)index; 
} 

。インデクサーはコンパイラの魔法です。

class IndexedData 
{ 
    public double this[int index] 
    { 
     get { return (double)index; } 
    } 

    public double get_Item(int index) 
    { 
     return 1d; 
    } 
} 
+0

ではなく、インデックス値を反復処理します。文字列はすでにchar型のインデックス付きパラメータです。 私はしたいと思います: 'foreach(char c in str)Console.write(c);'、リフレクションのみ... –

+0

@ Dead.Rabit:See私の編集。私はそれがインデクサーを理解するのに役立つと思います。 –

1

改善、心を作るために管理され、また、このテストコードは、それが今から継承する事を見つけ一言で言えば、自己参照のための無限ループ(例えばArray.Syncroot)

に苦しんでいることが判明IEnumerable(最も索引付けされているもの)であり、それらのforeachループを使用し、既存の(醜い)コードが文字列のために働くという知識と結びついて、今度はもっと徹底的に割り当てられています...

glad but素敵な答えがないように思えます。ヘルプみんな


更新されたテストコードの

おかげで、誰かがこの質問に同様の位置

static void process(object obj) 
    { 
     Type type = obj.GetType(); 

     PropertyInfo[] properties = type.GetProperties(); 

     // if this obj has sub properties, apply this process to those rather than this. 
     if (properties.Length > 0) 
     { 
      foreach (PropertyInfo prop in obj.GetType().GetProperties()) 
      { 
        if (prop.PropertyType.FindInterfaces((t, c) => t == typeof(IEnumerable), null).Length > 0) 
        { 
         MethodInfo accessor = prop.GetGetMethod(); 
         MethodInfo[] accessors = prop.GetAccessors(); 

         foreach (object item in (IEnumerable)obj) 
         { 
          process(item); 
         } 
        } 
        else if (prop.GetIndexParameters().Length > 0) 
        { 
         // get an integer count value, by incrementing a counter until the exception is thrown 
         int count = 0; 
         while (true) 
        { 
         try 
         { 
          prop.GetValue(obj, new object[] { count }); 
          count++; 
         } 
         catch (TargetInvocationException) { break; } 
        } 

        for (int i = 0; i < count; i++) 
        { 
         // process the items value 
         process(prop.GetValue(obj, new object[] { i })); 
        } 
       } 
       else 
       { 
        // is normal type so. 
        process(prop.GetValue(obj, null)); 
       } 
      } 
     } 
     else 
     { 
      // process to be applied to each property 
      Console.WriteLine("Property Value: {0}", obj.ToString()); 
     } 
    } 
0

上記のコードと関連するもので自分自身を見つけた場合は、問題のために本当に便利でした私は直面していた。私は自分のコードを投稿しています。このコードもあなたのために働くことを願っています。 `オブジェクト列str =新しいStringの目的は何

public ActionResult Survey(SurveyCollection surveyCollection) { if (surveyCollection != null) { Answer_DropDownCordinateOptionList traceObject = new Answer_DropDownCordinateOptionList(); IList traceObjectCollection = new List(); traceObjectCollection = ExtractNestedObjects(surveyCollection, traceObject, traceObjectCollection); }

return View(surveyCollection); 
} 

private static IList<T> ExtractNestedObjects<T>(object baseObject, T findObject, IList<T> resultCollection) 
{ 
    if (baseObject != null && findObject != null) 
    { 
     Type typeDestination = findObject.GetType(); 

     Type typeSource = baseObject.GetType(); 
     PropertyInfo[] propertyInfoCollection = typeSource.GetProperties(); 
     foreach (PropertyInfo propertyInfo in propertyInfoCollection) 
     { 
      if (propertyInfo.PropertyType.FindInterfaces((t, c) => t == typeof(IEnumerable), null).Length > 0) 
      { 
       if(propertyInfo.GetValue(baseObject, null) != null) 
       { 
        if(propertyInfo.GetValue(baseObject, null).GetType().IsPrimitive) 
        { 
         ExtractNestedObjects<T>(propertyInfo.GetValue(baseObject, null), findObject, resultCollection); 
        } 
        else if (propertyInfo.GetValue(baseObject, null).GetType().IsGenericType) 
        { 
         foreach (var item in (IList)propertyInfo.GetValue(baseObject, null)) 
         { 
          ExtractNestedObjects<T>(item, findObject, resultCollection); 
         } 
        } 
       } 
      } 
      else 
      { 
       if (propertyInfo.Name == typeDestination.Name) 
       { 
        if (propertyInfo.GetValue(baseObject, null) != null) 
        { 
         resultCollection.Add((T)propertyInfo.GetValue(baseObject, null)); 
        } 
       } 

       ExtractNestedObjects<T>(propertyInfo.GetValue(baseObject, null), findObject, resultCollection); 
      } 
     } 
    } 
    return resultCollection; 
} 

関連する問題