2011-01-06 5 views
8

Tengo una lista de objetos, de la cual no puedo saber el tipo de en tiempo de compilación.Cómo obtener la propiedad Count usando reflection para los tipos genéricos

Necesito identificar cualquiera de estos objetos donde existe una propiedad 'Contar', y obtener el valor si lo hace.

Este código funciona para este tipo sencillo de colección:

PropertyInfo countProperty = objectValue.GetType().GetProperty("Count"); 
if (countProperty != null) 
{ 
    int count = (int)countProperty.GetValue(objectValue, null); 
} 

El problema es que esto no funciona para los tipos genéricos, tales como IDictionary<TKey,TValue>. En esos casos, el valor 'countProperty' se devuelve como nulo, aunque exista una propiedad 'Count' en el objeto instanciado.

Todo lo que quiero hacer es identificar cualquier colección/objeto basado en diccionario y encontrar su tamaño, si tiene uno.

Editar: conforme a lo solicitado, aquí está la lista completa de código que no funciona

private static void GetCacheCollectionValues(ref CacheItemInfo item, object cacheItemValue) 
{ 
    try 
     { 
     //look for a count property using reflection 
     PropertyInfo countProperty = cacheItemValue.GetType().GetProperty("Count"); 
     if (countProperty != null) 
     { 
      int count = (int)countProperty.GetValue(cacheItemValue, null); 
      item.Count = count; 
     } 
     else 
     { 
      //poke around for a 'values' property 
      PropertyInfo valuesProperty = cacheItemValue.GetType().GetProperty("Values"); 
      int valuesCount = -1; 
      if (valuesProperty != null) 
      { 
       object values = valuesProperty.GetValue(cacheItemValue, null); 
       if (values != null) 
       { 
        PropertyInfo valuesCountProperty = values.GetType().GetProperty("Count"); 
        if (countProperty != null) 
        { 
         valuesCount = (int)valuesCountProperty.GetValue(cacheItemValue, null); 
        } 
       } 
      } 
      if (valuesCount > -1) 
       item.Count = valuesCount; 
      else 
       item.Count = -1; 
     } 
    } 
    catch (Exception ex) 
    { 
     item.Count = -1; 
     item.Message = "Exception on 'Count':" + ex.Message; 
    } 
} 

Esto funciona bien en colecciones simples, pero no en un objeto creado a partir de una clase que tengo que se deriva de Dictionary<TKey,TValue> . Es decir

CustomClass : 
    Dictionary<TKey,TValue> 

CacheItemInfo es sólo una clase simple que contiene propiedades para elementos de caché - es decir, llave, contar, tipo, de caducidad de fecha y hora

+0

(pensando en términos de 'IDictionary 'no ayudará aquí, ya que' GetType() 'siempre devolverá el tipo * concrete *, que podría ser cualquier cosa, pero es más probable' Dictionary ') –

+0

Aquí está el código como permanece - todavía no funciona. –

+0

Así que la respuesta fue ignorar la reflexión y simplemente enviar a las interfaces; ver la respuesta correcta a continuación. –

Respuesta

11

Lo primero que se debe tratar es la fundición a ICollection, ya que este tiene una muy barato .Count:

ICollection col = objectValue as ICollection; 
if(col != null) return col.Count; 

El Count para el diccionario debería funcionar, aunque - he probado esto con Dictionary<,> y funciona bien - pero tenga en cuenta que incluso si algo implementa IDictionary<,>, el hormigón tipo (que se obtiene a través de GetType()) no tiene que tener una .Count en la API pública - que podría utilizar implementación de interfaz explícita para satisfacer la interfaz, mientras que no tener un public int Count {get;}. Como digo: funciona para Dictionary<,>, pero no necesariamente para todos los tipos.

Como un último esfuerzo si todo lo demás falla:

IEnumerable enumerable = objectValue as IEnumerable; 
if(enumerable != null) 
{ 
    int count = 0; 
    foreach(object val in enumerable) count++; 
    return count; 
} 

Editar para examinar la cuestión Dictionary<,> criado en los comentarios:

using System; 
using System.Collections; 
using System.Collections.Generic; 
public class CustomClass : Dictionary<int, int> { } 
public class CacheItemInfo 
{ 
    public int Count { get; set; } 
    public string Message { get; set; } 
} 
class Program { 
    public static void Main() { 
     var cii = new CacheItemInfo(); 
     var data = new CustomClass { { 1, 1 }, { 2, 2 }, { 3, 3 } }; 
     GetCacheCollectionValues(ref cii, data); 
     Console.WriteLine(cii.Count); // expect 3 
    } 
    private static void GetCacheCollectionValues(ref CacheItemInfo item, object cacheItemValue) 
    { 
     try 
     { 
      ICollection col; 
      IEnumerable enumerable; 
      if (cacheItemValue == null) 
      { 
       item.Count = -1; 
      } 
      else if ((col = cacheItemValue as ICollection) != null) 
      { 
       item.Count = col.Count; 
      } 
      else if ((enumerable = cacheItemValue as IEnumerable) != null) 
      { 
       int count = 0; 
       foreach (object val in enumerable) count++; 
       item.Count = count; 
      } 
      else 
      { 
       item.Count = -1; 
      } 
     } 
     catch (Exception ex) 
     { 
      item.Count = -1; 
      item.Message = "Exception on 'Count':" + ex.Message; 
     } 
    } 
} 
+0

Marc - gracias por su contribución.He descubierto que he omitido detalles importantes de mi pregunta original: una de las clases que estoy viendo deriva del Diccionario y esa es una de las que no funciona con .Count(). Menciona pruebas con IDictionary <,> - ¿puede publicar el código que utilizó con eso? –

+0

@Bruce - Probé con 'Dictionary <,>' - el tipo concreto (las interfaces son irrelevantes directamente con 'GetType()' - y aún debería funcionar con una subclase de eso. ¿Puede mostrar código que * no * funciona? Acabo de aprobar en un diccionario. –

+0

Marc: disculpa por la demora que tuvo que enviar de todos modos. He publicado el código completo que estoy usando, todavía no funciona con los elementos del diccionario. –

1

Cómo sobre la adición de esto después de su primer cheque (! no probado!) ...

foreach (Type interfaceType in objectValue.GetType().GetInterfaces()) 
{ 
    countProperty = interfaceType.GetProperty("Count"); 
    //etc. 
} 
Cuestiones relacionadas