2011-01-06 9 views
8

Ich habe eine Liste von Objekten, von denen ich den Typ von zur Kompilierzeit nicht kennen kann.So erhalten Sie die Count-Eigenschaft mit Reflektion für generische Typen

Ich muss eines dieser Objekte identifizieren, wo eine "Count" -Eigenschaft vorhanden ist, und den Wert erhalten, wenn dies der Fall ist.

Dieser Code funktioniert für einfache Art der Sammlung:

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

Das Problem ist, dass dies nicht für generische Typen funktioniert, wie IDictionary<TKey,TValue>. In diesen Fällen wird der Wert "countProperty" als null zurückgegeben, obwohl im instanzierten Objekt eine Eigenschaft "Count" vorhanden ist.

Alles, was ich tun möchte, ist jede Sammlung/Dictionary-basierten Objekt identifizieren und finden Sie die Größe, wenn es eine hat.

Edit: wie gewünscht, hier ist die gesamte Auflistung der Code, der nicht

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

Dies funktioniert OK auf einfache Sammlungen funktioniert, aber nicht auf ein Objekt aus einer Klasse habe ich geschaffen, die von Dictionary<TKey,TValue> stammt . Dh

CustomClass : 
    Dictionary<TKey,TValue> 

CacheItemInfo ist nur eine einfache Klasse, die Eigenschaften für die Cache-Elemente enthält - dh Schlüssel, Anzahl, Art, Ablaufdatumzeit

+0

(Denken in Begriffen von IDictionary 'wird hier nicht helfen, da' GetType() 'immer den * konkreten * Typ zurückgibt, der alles sein könnte, aber ist am wahrscheinlichsten' Dictionary –

+0

Hier ist der Code als Es steht - funktioniert immer noch nicht. –

+0

Also war die Antwort, Reflexion zu ignorieren und nur auf Schnittstellen zu werfen - siehe richtige Antwort unten. –

Antwort

11

Das erste, was Sie sollten versuchen, auf ICollection Gießen, da dies eine hat sehr billig .Count:

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

Die Count für Wörterbuch sollte allerdings arbeiten - ich habe diese getestet mit Dictionary<,> und es funktioniert gut - aber beachten sie, dass selbst wenn etwas implementiert IDictionary<,>, der Betons Typ (zurück über GetType()) nicht ein .Count auf der öffentlichen API haben - es explizite Schnittstellenimplementierung verwenden könnte die Schnittstelle zu erfüllen, während nicht ein public int Count {get;} hat. Wie ich schon sagte: es funktioniert für Dictionary<,> - aber nicht unbedingt für jeden Typ.

Als letzten verzweifelten Versuch, wenn alles andere fehlschlägt:

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

bearbeiten schauen in die Dictionary<,> Frage in den Kommentaren aufgeworfen:

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 - danke für deinen Beitrag.Ich habe festgestellt, dass ich wichtige Details aus meiner ursprünglichen Frage weggelassen habe - eine der Klassen, die ich betrachte, stammt aus dem Wörterbuch und das ist eines der Dinge, die nicht mit .Count() funktionieren. Sie erwähnen Tests mit IDictionary <,> - können Sie den Code, den Sie damit gebucht haben? –

+0

@Bruce - Ich testete mit 'Dictionary <,>' - der konkrete Typ (Schnittstellen sind irrelevant direkt mit 'GetType()' - und es sollte immer noch mit einer Unterklasse davon funktionieren. Können Sie Code anzeigen, der * nicht * funktioniert? Ich habe gerade in einem Wörterbuch bestanden. –

+0

Marc - Entschuldigung über die Verzögerung musste sowieso versenden. Ich habe den vollen Code, den ich benutze, gepostet, es funktioniert immer noch nicht mit den Wörterbuchelementen. –

1

Wie über das Hinzufügen dieser nach dem ersten Check (! ungetestet!) ...

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