2009-06-25 4 views
88

Ich arbeite an einem Reflexionsprojekt, und jetzt stecke ich fest. Wenn ich ein Objekt von "myclass" habe, das eine Liste enthalten kann weiß jemand, wie man den Typ wie im folgenden Code erhält, wenn die Eigenschaft myclass.SomList leer ist?C# generische Liste <T> Wie bekomme ich die Art von T?

List<myclass> myList = dataGenerator.getMyClasses(); 
lbxObjects.ItemsSource = myList; 
lbxObjects.SelectionChanged += lbxObjects_SelectionChanged; 

private void lbxObjects_SelectionChanged(object sender, SelectionChangedEventArgs e) 
     { 
      Reflect(); 
     } 
Private void Reflect() 
{ 
foreach (PropertyInfo pi in lbxObjects.SelectedItem.GetType().GetProperties()) 
{ 
     switch (pi.PropertyType.Name.ToLower()) 
     { 
     case "list`1": 
      {   
      // This works if the List<T> contains one or more elements. 
      Type tTemp = GetGenericType(pi.GetValue(lbxObjects.SelectedItem, null)); 

      // but how is it possible to get the Type if the value is null? 
      // I need to be able to create a new object of the type the generic list expect. 
      // Type type = pi.getType?? // how to get the Type of the class inside List<T>? 
      break; 
      } 
     } 
} 
} 
private Type GetGenericType(object obj) 
     { 
      if (obj != null) 
      { 
       Type t = obj.GetType(); 
       if (t.IsGenericType) 
       { 
        Type[] at = t.GetGenericArguments(); 
        t = at.First<Type>(); 
       } return t; 
      } 
      else 
      { 
       return null; 
      } 
     } 

Antwort

174
Type type = pi.PropertyType.PropertyType; 
if(type.IsGenericType && type.GetGenericTypeDefinition() 
     == typeof(List<>)) 
{ 
    Type itemType = type.GetGenericArguments()[0]; // use this... 
} 

Allgemeiner unterstützen jede IList<T>, müssen Sie die Schnittstellen überprüfen:

foreach (Type interfaceType in type.GetInterfaces()) 
{ 
    if (interfaceType.IsGenericType && 
     interfaceType.GetGenericTypeDefinition() 
     == typeof(IList<>)) 
    { 
     Type itemType = type.GetGenericArguments()[0]; 
     // do something... 
     break; 
    } 
} 
+8

sollte es nicht Typ itemType = interfaceType.GetGenericArguments sein() [0]; – Muxa

+0

Amüsant schlägt das zweite Beispiel mit, sagen wir 'IList '. Fix unter http://StackOverflow.com/a/13608408/284795 –

+0

Ich weiß, dass die Antwort sehr alt ist, aber ich versuche, Folgendes zu verstehen: 'GetGenericArguments() [0];' Warum gibt es die 0? Gibt es im Type [] immer nur einen Eintrag? – Ismoh

7

Marcs Antwort ist der Ansatz, den ich für diesen Einsatz, aber der Einfachheit halber (und eine freundlichere API?) Sie können eine Eigenschaft in der Sammlung Basisklasse definieren, wenn Sie eine wie haben:

public abstract class CollectionBase<T> : IList<T> 
{ 
    ... 

    public Type ElementType 
    { 
     get 
     { 
     return typeof(T); 
     } 
    } 
} 

Ich habe diesen Ansatz nützlich gefunden, und ist leicht für alle Neueinsteiger in Generika zu verstehen.

+0

Ich wollte diesen Ansatz verwenden, aber dann erkannte ich, dass ich die Listeninstanz haben muss, um den Elementtyp zu bestimmen, den ich nicht immer haben werde. – Muxa

+1

können Sie die Eigenschaft statisch machen.Wie "public static Type ElementType" ... dann erhalten Sie es als "var t = CollectionBase .ElementType;" ... benötigen Sie keine Instanzvariable – Nabheet

+0

True. Mit Static können Sie mit einer Klasse ohne vorhandenes Objekt arbeiten. Ich finde diesen Ansatz einfacher zu handhaben. Sicher, Sie müssen zusätzliche Informationen in Ihren Objekten speichern, aber zumindest ersparen Sie sich diesen Kaskadenanruf in der genehmigten Antwort. – rbaleksandar

4

ein Objekt gegeben, die ich vermute, eine Art von IList<> zu sein, wie kann ich feststellen, was es ein IList<> ist?

Hier ist eine zuverlässige Lösung. Ich entschuldige mich für die Länge - C# 's Introspection API macht dies überraschend schwierig.

/// <summary> 
/// Test if a type implements IList of T, and if so, determine T. 
/// </summary> 
public static bool TryListOfWhat(Type type, out Type innerType) 
{ 
    Contract.Requires(type != null); 

    var interfaceTest = new Func<Type, Type>(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>) ? i.GetGenericArguments().Single() : null); 

    innerType = interfaceTest(type); 
    if (innerType != null) 
    { 
     return true; 
    } 

    foreach (var i in type.GetInterfaces()) 
    { 
     innerType = interfaceTest(i); 
     if (innerType != null) 
     { 
      return true; 
     } 
    } 

    return false; 
} 

Beispiel Nutzung:

object value = new ObservableCollection<int>(); 
Type innerType; 
TryListOfWhat(value.GetType(), out innerType).Dump(); 
innerType.Dump(); 

Returns

True 
typeof(Int32) 
+0

Ich sehe kein anderes Ergebnis als Marcs-Methode (auch mit Marcs bekomme ich Int32) – Offler

17

ein Objekt gegeben, die ich vermute, eine Art von IList<> zu sein, wie ich was bestimmen kann, es ist ein IList<> ?

Hier ist die mutige Lösung. Es wird davon ausgegangen, dass Sie das eigentliche zu testende Objekt haben (statt einer Type).

public static Type ListOfWhat(Object list) 
{ 
    return ListOfWhat2((dynamic)list); 
} 

private static Type ListOfWhat2<T>(IList<T> list) 
{ 
    return typeof(T); 
} 

Beispiel Nutzung:

object value = new ObservableCollection<DateTime>(); 
ListOfWhat(value).Dump(); 

Drucke

typeof(DateTime) 
+0

-1: Warum 'IList ' statt 'IEnumerable '? Warum "dynamisch"? –

+0

Habe ich die Frage von OP falsch verstanden? Das Detail war unklar, also beantwortete ich die Frage im Titel. –

+3

Sie, Sir, sind ein Zauberer! Ich habe mir den Kopf zerbrochen, als ich versuchte, ein Problem mit einem dynamischen Parser mit einer generischen Datenstruktur zu lösen (die mit einzelnen Typen und Listen umgehen kann), und * dies * hat mich auf den richtigen Weg gebracht. –