2009-07-20 19 views
0

Ich versuche Reflektion zu verwenden, um Eigenschaften für einige OpenXML-Typen festzulegen (z. B. für die Rechtfertigung). Wert zuweisen, indem sie alle Möglichkeiten aufzuzählen ist straight-forward:Verwenden von Reflektion mit generischen Typen und impliziten Konvertierungen

// attr is an XmlAttribute, so .Name and .Value are Strings 
if (attr.Name == "Val") 
{ 
    if (element is Justification) 
    { 
     ((Justification)element).Val = (JustificationValues)Enum.Parse(typeof(JustificationValues), attr.Value); 
      return; 
    } 
    else 
    { 
     // test for dozens of other types, such as TabStop 
    } 
} 

Was diese schwierige durch Reflexion zu tun macht, ist: 1) Die Art des Val Eigenschaft ist EnumValue <T>, so weiß ich nicht, wie man den Typ extrahiert, der als erstes Argument an Enum.Parse übergeben wird. 2) Es gibt eine implizite Konvertierung vom tatsächlichen Enumerationstyp in den EnumValue < > Typ, den ich nicht weiß, wie ich mit Reflection aufrufe.

würde ich den Code gerne bis Ende etwas suchen, wie:

PropertyInfo pInfo = element.GetType().GetProperty(attr.Name); 
Object value = ConvertToPropType(pInfo.PropertyType, attr.Value); /* this 
    would return an instance of EnumValue<JustificationValues> in this case */ 
pInfo.SetValue(element, value, null); 

Wie kann ich ConvertToPropType implementieren? Oder gibt es eine bessere Lösung?

Dank

Edit: bekam ich eine Lösung mit Earwicker Vorschlag zu arbeiten, aber es stützt sich auf der praktischen Tatsache, dass die Typnamen der Aufzählung aus dem Typnamen des Knotens abgeleitet werden („Begründung“ -> „JustificationValues“). Ich bin aber immer noch neugierig, wie ich das im allgemeinen Fall lösen soll.

Edit2: GetGenericArguments hat mir den Rest des Weg dorthin. Vielen Dank.

+0

tun Haben Sie das Update auf meine Antwort zu sehen? Es zeigt, wie der Enum-Typ vom Eigenschaftstyp abgerufen wird. –

Antwort

4

Wenn der Attributwert nur eine Zeichenfolge ist, nehme ich an, Sie haben bereits eine Möglichkeit herauszufinden, dass die Zeichenfolge einen Wert aus einer bestimmten Aufzählung identifiziert. In Ihrem Beispiel haben Sie es hart codiert, also bin ich mir nicht sicher, ob Sie das wollen oder was Sie ändern wollen.

Angenommen, Sie wissen, dass es eine Aufzählung ist und Sie wissen, welche Aufzählung Sie wissen, wie Sie ein Objekt mit einem Boxed-Wert des richtigen enum Typs erhalten, wie in Ihrem Schnipsel.

Nun, wenn ich davon ausgehe EnumValue<T> hat einen Konstruktor, der eine T nimmt.

Type genericType = typeof(EnumValue<>); 
Type concreteType = genericType.MakeGenericType(typeof(JustificationValues)); 

Jetzt ist concreteType der Typ EnumValue<JustificationValues>.

Von diesem können Sie einen Konstruktor erhalten, hoffentlich einen, der einen JustificationValues Parameter und Invoke es nimmt.

aktualisieren

Ahh, ich sehe, was Sie jetzt tun. Sie verwenden den XML-Attributnamen, um eine C# -Eigenschaft auszuwählen. Sie müssen erkennen können, ob diese Eigenschaft vom Typ EnumValue<T> ist, und herausfinden, was T ist.

PropertyInfo p = // ... get property info 

Type t = p.GetType(); 

if (t.IsGenericType && 
    t.GetGenericTypeDefinition == typeof(EnumValue<>)) 
{ 
    Type e = t.GetGenericArguments()[0]; // get first (and only) type arg 

    // e is the enum type... 

Probieren Sie es aus.

+0

Ich kenne den Aufzählungstyp im Allgemeinen nicht, es hängt vom Typ des Elements ab. Ich wusste nicht über MakeGenericType, aber ich glaube nicht, dass ich in der Lage sein werde, es zu verwenden, bis ich herausfinden, wie man den Typ T aus einem Typ EnumValue bmm6o

+0

Entschuldigung, ich hatte verpasst, dass Sie die Eigenschaft nachschlagen Verwenden des Attributnamens. –

1

.Net 4.0 fügt Unterstützung hinzu, um eine späte gebundene implizite oder explizite Konvertierung durchzuführen. Dies wird im Open-Source-Framework ImpromptuInterface mit seiner statischen Methode InvokeConvert vereinfacht.In Ihrem idealen Beispiel würde es so funktionieren:

PropertyInfo pInfo = element.GetType().GetProperty(attr.Name); 
Object value = Impromptu.InvokeConvert(attr.Value, pInfo.PropertyType); 
pInfo.SetValue(element, value, null); 
1

Dies ist nur mit Grundtypen funktionieren kann, aber es war gut genug für das, was ich

PropertyInfo pInfo = element.GetType().GetProperty(attr.Name); 
Object value = System.Convert.ChangeType(attr.Value, pInfo.PropertyType); 
pInfo.SetValue(element, value, null); 
Verwandte Themen