2010-11-24 14 views
8

Quiero itterate más de una propiedad indizada que sólo tengo acceso a través de la reflexión,iteración a través de una propiedad indexada (Reflexión)

pero (y lo digo en el pleno conocimiento de que es probable que haya una respuesta vergonzosamente simple, MSDN/Google fail = /) No puedo encontrar/pensar en una forma además de incrementar un contador en el PropertyInfo.GetValue(prop, counter) hasta que se arroje el TargetInvocationException.

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

ahora, hay algunos problemas con esto ... muy feo .. .. solución

¿y si es multidimensional o no indexados por números enteros, por ejemplo ..

Aquí está el código de prueba que estoy usando para intentar que funcione si alguien lo necesita. Si alguien está interesado, estoy haciendo un sistema de caché personalizado y .Equals no lo corta.

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

¿Cuál es el propósito de 'str objeto = new String (("Hola, mundo"). ToArray())'? –

+0

solo una variable de ejemplo para pasar a mi función ... estaba probando las diferentes formas de definir una cadena/String y la dejé en un poco incómodo ... 'object str =" Hello, World! ";' funciona igual de bien. –

+0

¿Qué hacer si tengo claves STRING, no enteros? No sé sus nombres. ¿Cómo encontrarlos y usarlos? – Alexander

Respuesta

8

El captador de un indexador es como el método normal, excepto que se trata de corchetes, no de corchetes. No esperaría poder determinar automáticamente el rango de valores aceptables para un método, por lo que no es factible para un indexador.

+0

Una solución consiste en utilizar la reflexión para buscar una propiedad de miembro llamada 'Longitud' o' Cuenta' y usarla como el límite superior para propiedades de índice entero, o una propiedad llamada 'Llaves' para una propiedad indexada por cadenas. – Dai

2

Puede utilizar PropertyInfo.GetIndexParameters para averiguar el número y tipo de parámetros de propiedades indizadas.

No creo que haya nada que pueda hacer para encontrar los valores "legales" para estos parámetros, a menos que "engañe" y use la información interna que pueda tener sobre la propiedad.

3

Tener números de índice secuenciales en una propiedad indexada no es nada en lo que pueda apostar.
Las propiedades indexadas no son matrices.
ejemplo Contador:

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

Dependiendo del tipo por lo general tienen otros métodos para obtener los posibles valores del índice, en este caso dictionary.Keys. Si es posible con sus tipos lo probaría en este orden

  1. Implemente IEnumerable<T> para el tipo en sí.
  2. Si tiene varias propiedades indexadas, puede implementar una propiedad correspondiente IEnumerable<T> para cada propiedad indexada.

Si no tiene una especificación de valores válidos ni un método para preguntar cuáles son los valores válidos, entonces no tiene suerte.

+0

Desafortunadamente, soy nieve del tipo de entrada hasta el tiempo de ejecución (en realidad está implementado como un método de extensión de objeto) pero me dio la idea de buscar una implementación de IEnumerable. Gracias –

4

Los indexadores se compilarán según los métodos. He aquí un ejemplo:

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

Se compiló a algo como esto:

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

El siguiente código no se puede compilar porque hay dos double get_Item(int) métodos de la clase. Indexer es una magia del compilador.

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

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

en lugar de iterar a través de los valores indexados. string ya es un parámetro indexado de tipo char ... así que quería hacer: 'foreach (char c en str) Console.write (c);', solo con reflexión .. –

+0

@ Dead.Rabit: See mi edición. Creo que te ayudará a entender el indexador. –

1

arreglado para hacer una mejora, la mente, también se descubrió que este código de prueba sufre de bucles infinitos para las referencias de uno mismo (Array.Syncroot por ejemplo)

En pocas palabras ahora se encuentra cosas que heredan de IEnumerable (que es la mayoría de las cosas indexadas) y utiliza un bucle Foreach en esos y junto con el conocimiento de que el código existente (feo) funciona para cadenas, ahora es más completo de lo que solía ser ...

contenta pero decepcionado de que no parece haber una buena respuesta.

Gracias por la ayuda de todos


Actualizado código de prueba, si alguien se encuentra en una posición similar

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

Los códigos anteriores y las relacionadas con esta cuestión eran realmente útiles para el problema que estaba enfrentando Estoy publicando mi código y espero que este funcione para ustedes también.

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

Cuestiones relacionadas