2010-11-24 3 views
8

Я хочу itterate над индексированным свойством, что я только иметь доступ к с помощью отражения,перебор индексированного свойства (Отражение)

, но (и я говорю это с полным осознанием того, что есть, вероятно, ошеломляюще простой ответ, MSDN/Google fail = /) Я не могу найти/подумать об этом, не увеличивая счетчик по PropertyInfo.GetValue(prop, counter) до тех пор, пока не будет выброшен TargetInvocationException.

ала:

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

сейчас, есть некоторые проблемы с этим ... очень некрасиво .. решение ..

что, если это многомерный или не индексируются целыми числами, например .. .

heres тестовый код, который я использую, чтобы попытаться заставить его работать, если кому-то это нужно. Если кому-то интересно, я создаю пользовательскую систему кеширования и .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

Что цель `объекта ул = новая строка (("Hello, World"). ToArray())`? – 2010-11-24 15:24:16

+0

просто переменная примера, передаваемая моей функции ... пыталась использовать различные способы определения строки/String и оставила ее на некотором неудобном ... `object str =" Hello, World! ";` работает так же хорошо. – 2010-11-24 15:35:10

+0

Что делать, если у меня есть клавиши STRING, а не целое число? Я не знаю их имен. Как их найти и использовать? – Alexander 2017-12-07 20:51:47

ответ

8

Получатель индексатора точно так же, как и обычный метод, за исключением того, что он принимает квадратные скобки, а не круглые. Вы не ожидали бы, что сможете автоматически определить диапазон допустимых значений для метода, поэтому это не представляется возможным для индексатора.

+0

Обходным путем является использование отражения для поиска свойства-члена, называемого `Length` или` Count`, и использовать его как верхний для индексированных по целому классу свойств или свойство, называемое `Keys` для свойства с индексом строки. – Dai 2012-09-05 01:18:58

2

Вы можете использовать PropertyInfo.GetIndexParameters, чтобы выяснить количество и тип параметров индексированных свойств.

Я не думаю, что вы можете что-то сделать, чтобы найти, какие «законные» значения для этих параметров есть, если вы не «обманываете» и не используете внутреннюю информацию, которую вы можете иметь о том, что это за свойство.

3

Последовательные номера индексов в индексированном свойстве - это то, на что вы можете делать ставки.
Индексированные свойства не являются массивами.
пример Счетчик:

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

В зависимости от типа вы обычно есть другие методы, чтобы получить возможные значения индекса, в данном случае dictionary.Keys. Если возможно, с вашими типами я бы поставил в этом порядке

  1. Внесите IEnumerable<T> для самого типа.
  2. Если у вас есть несколько индексированных свойств, вы можете реализовать соответствующее свойство IEnumerable<T> для каждого индексированного свойства.

Если у вас нет спецификации действительных значений и нет способа задать правильные значения, то вам в значительной степени не повезло.

4

Индексаторы будут скомпилированы к методам. Вот пример:

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

Он будет составлен на что-то вроде этого:

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

Следующий код не может быть скомпилирован, потому что есть два double get_Item(int) методы в классе. Indexer - это волшебство компилятора.

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

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

Успел сделать улучшение, ум, а также выяснил, что этот тестовый код страдает от бесконечных петель для самостоятельных ссылок (например Array.Syncroot)

В двух словах теперь находят вещи, которые наследуют от IEnumerable (это наиболее индексированные вещи) и использует для них цикл foreach, а также знание того, что существующий (уродливый) код работает для строк, теперь он более подробный, чем раньше ...

рад, но разочарован тем, что, похоже, нет хорошего ответа.

Спасибо за помощь всем


Обновленный тестовый код, если кто-то находит себя в таком же положении

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

Вышеуказанные коды и связанные с ними те, чтобы этот вопрос был действительно полезным для задачи что я столкнулся. Я отправляю свой код, и я надеюсь, что он тоже работает для вас, ребята.

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

Смежные вопросы