2012-10-01 6 views
19

Ich entschuldige mich, wenn das irgendwo abgedeckt ist. Ich habe vor dem Posten recherchiert!Wie bekomme ich Felder und Eigenschaften im Einzelaufruf über Reflektion?

OK, also Frage ... Ich benutze GetType() .GetProperties, aber es gibt keine einfachen Instanzfelder, die nicht get/set auf ihnen haben ... so habe ich .GetFields verwendet, das findet sie, aber ich möchte ein einfaches einzelnes Objekt bekommen, um einen Wert zu erhalten/setzen, ohne zwischen Feldern und Eigenschaften zu wechseln ... ist das möglich?

mein aktueller Code funktioniert auf PropertyInfo, das funktioniert gut, aber das ist nicht für Felder, denke ich?

[bearbeiten] Dies ist die Lösung, die ich kam, die gut funktioniert. Dank jeder ....

// some logic borrowed from James Newton-King, http://www.newtonsoft.com 
    public static void SetValue(this MemberInfo member, object property, object value) 
    { 
     if (member.MemberType == MemberTypes.Property) 
      ((PropertyInfo)member).SetValue(property, value, null); 
     else if (member.MemberType == MemberTypes.Field) 
      ((FieldInfo)member).SetValue(property, value); 
     else 
      throw new Exception("Property must be of type FieldInfo or PropertyInfo"); 
    } 

    public static object GetValue(this MemberInfo member, object property) 
    { 
     if (member.MemberType == MemberTypes.Property) 
      return ((PropertyInfo)member).GetValue(property, null); 
     else if (member.MemberType == MemberTypes.Field) 
      return ((FieldInfo)member).GetValue(property); 
     else 
      throw new Exception("Property must be of type FieldInfo or PropertyInfo"); 
    } 

    public static Type GetType(this MemberInfo member) 
    { 
     switch (member.MemberType) 
     { 
      case MemberTypes.Field: 
       return ((FieldInfo)member).FieldType; 
      case MemberTypes.Property: 
       return ((PropertyInfo)member).PropertyType; 
      case MemberTypes.Event: 
       return ((EventInfo)member).EventHandlerType; 
      default: 
       throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member"); 
     } 
    } 

Antwort

22

Wie sei:

const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance; 
MemberInfo[] members = type.GetFields(bindingFlags).Cast<MemberInfo>() 
    .Concat(type.GetProperties(bindingFlags)).ToArray(); 

Alternativ Bibliotheken wie FastMember werden entweder mit Feldern oder Eigenschaften glücklich arbeiten, mit get/set identisch, unabhängig von dem Element-Typ.

+0

Von OP: "Erhalten Sie ein einfaches einzelnes Objekt, um einen Wert zu erhalten/setzen". Ich bin mir nicht sicher, wie MemberInfo das macht. – CrazyCasta

+1

@CrazyCasta tatsächlich; Wenn Sie das wollen, müssen Sie die Core-Reflection-API verlassen, da es keine einzige gemeinsame Schnittstelle dafür gibt. Es existieren jedoch separate Bibliotheken, weshalb ich FastMember zitierte. –

+1

Ich möchte sowohl @CrazyCasta als auch marc als Antworten markieren, da sie beide hilfreich sind, aber letztendlich habe ich mit der MemberInfo die Erweiterungsmethoden verwendet. – Timmerz

10

Die Rückgabetypen von GetProperties() und GetFields() unterschiedlich sind, wie Sie bemerkt zu haben scheinen. Sie müssten eine Schnittstelle mit GetValue() und SetValue() definieren und mit extent ParameterInfo und FieldInfo diese Schnittstelle implementieren. Dies würde wahrscheinlich als Wrapper arbeiten:

interface IGetSettable 
{ 
    public void SetValue(
     Object obj, 
     Object value, 
     Object[] index); 
    public Object GetValue(
     Object obj, 
     Object[] index); 
} 

public class ParameterInfoGS : IGetSettable 
{ 
    protected ParameterInfo pi; 

    public ParameterInfoExtra(ParameterInfo _pi) 
    { 
     pi = _pi; 
    } 

    public void SetValue(
     Object obj, 
     Object value, 
     Object[] index) {pi.SetValue(obj, value, index);} 
    public Object GetValue(
     Object obj, 
     Object[] index) {return pi.GetValue(obj, index);} 
} 

public class FieldInfoGS : IGetSettable 
{ 
    protected FieldInfo pi; 

    public FieldInfoExtra(FieldInfo _pi) 
    { 
     pi = _pi; 
    } 

    public void SetValue(
     Object obj, 
     Object value, 
     Object[] index) {pi.SetValue(obj, value, index);} 
    public Object GetValue(
     Object obj, 
     Object[] index) {return pi.GetValue(obj, index);} 
} 

public static class AssemblyExtension 
{ 
    public static IGetSettable[] GetParametersAndFields(this Type t) 
    { 
     List<IGetSettable> retList = new List<IGetSettable>(); 

     foreach(ParameterInfo pi in t.GetParameters()) 
      retList.Add(new ParameterInfoExtra(pi)); 

     foreach(FieldInfo fi in t.GetFields()) 
      retList.Add(new FieldInfoExtra(fi)); 

     return retList.ToArray(); 
    } 
} 

Diese Sie GetType().GetParametersAndFields() tun können (das heißt die Standard-Reflexionstypen verwenden).

+3

'MemberInfo'; p –

+4

@MarcGravell Das hat keine Methoden zum Abrufen und Festlegen. – CrazyCasta

2

Mit DLR (einfach genug, wenn Sie den Namen des Mitglieds bei der Kompilierung kennen):

((dynamic)obj).MyFieldOrPropertyName = myValue; 

Wenn Sie nur den Namen des Mitglieds bei Laufzeit wissen, ich würde FastMember empfehlen, da Marc Gravell schlug vor.

6

Ein bisschen spät, aber ich kam mit der folgenden ... 1 Schleife auf, wirkt wie ein Zauber ;-)

 MemberInfo[] memberInfos = dotNetType.GetMembers(); 
     ModelPropertySpec modelPropertySpec; 
     foreach (MemberInfo memberInfo in memberInfos) 
     { 
      Type itemType = null; 
      String memberName = memberInfo.Name; 
      switch (memberInfo.MemberType) 
      { 
       case MemberTypes.Property: 
        itemType = dotNetType.GetProperty(memberName).PropertyType; 
        break; 
       case MemberTypes.Field: 
        itemType = dotNetType.GetField(memberName).FieldType; 
        break; 
      } 

      if (itemType != null) 
      { 
       modelPropertySpec = ParsePropertyType(memberName, itemType); 
       modelSpec.Properties.Add(modelPropertySpec.Name, modelPropertySpec); 
      } 
     } 
5

entweder Eigenschaften oder Felder zu erhalten, können Sie sagen:

var q= 
    from it in type.GetMembers(bindingAttr) 
    where it is PropertyInfo||it is FieldInfo 
    select it; 

wo bindingAttr könnte

var bindingAttr= 
     BindingFlags.NonPublic| 
     BindingFlags.Public| 
     BindingFlags.Instance; 

BindingFlags.NonPublic entfernen, wenn Sie nicht-pu nicht bekommen wollen blic Mitglieder. Übrigens ist die Abfrage kein einzelner Anruf sondern eine einzige Anweisung.


Um den Wert entweder eine Eigenschaft oder ein Feld, ohne es selbst zu werfen, verwenden InvokeMember für den Trick:

static object GetValue<T>(
     T x, object target) where T:MemberInfo { 
    var invokeAttr=(
      x is FieldInfo 
       ?BindingFlags.GetField 
       :x is PropertyInfo 
        ?BindingFlags.GetProperty 
        :BindingFlags.Default)| 
      BindingFlags.NonPublic| 
      BindingFlags.Public| 
      BindingFlags.Instance; 

    return target.GetType().InvokeMember(
     x.Name, invokeAttr, default(Binder), target, null); 
} 

In ähnlicher Weise den Wert einzustellen:

static void SetValue<T>(
     T x, object target, object value) where T:MemberInfo { 
    var args=new object[] { value }; 
    var invokeAttr=(
      x is FieldInfo 
       ?BindingFlags.SetField 
       :x is PropertyInfo 
        ?BindingFlags.SetProperty 
        :BindingFlags.Default)| 
      BindingFlags.NonPublic| 
      BindingFlags.Public| 
      BindingFlags.Instance; 

    target.GetType().InvokeMember(
     x.Name, invokeAttr, default(Binder), target, args); 
} 

Es wird geworfen, wenn Sie ein MemberInfo anderes als PropertyInfo oder FieldInfo als erstes Argument übergeben, weil BindingFlags.Default doesn ' t angeben, was Sie tun werden.

Verwandte Themen