2012-10-01 14 views
19

Przepraszam, jeśli jest to gdzieś ukryte. Zrobiłem badania przed opublikowaniem!jak uzyskać oba pola i właściwości w jednym wywołaniu za pomocą odbicia?

ok, więc pytanie ... Używam GetType() .GetProperties, ale nie zwraca pól proste instancji, które nie mają get/set na nich ... więc użyłem .GetFields, który je znajduje, ale chcę uzyskać prosty pojedynczy obiekt, aby uzyskać/ustawić wartość bez odwracania między polami i właściwościami ... czy to możliwe?

mój obecny kod działa na PropertyInfo, który działa świetnie, ale to nie jest dla pól, które myślę?

[edycja] to jest rozwiązanie, które wymyśliłem, które działa dobrze. Dzięki wszystkim ....

// 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"); 
     } 
    } 

Odpowiedz

22

Jak o:

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

Alternatywnie, biblioteki jak FastMember zadziała szczęśliwie albo z pól lub właściwości, z get/set identyczne niezależnie od typu członkowskim.

+0

Z OP: "uzyskaj prosty pojedynczy obiekt, aby uzyskać/ustawić wartość". Nie jestem pewien jak to robi MemberInfo. – CrazyCasta

+1

@CrazyCasta w rzeczy samej; jeśli chcesz, musisz wyjść poza rdzeń interfejsu API, ponieważ tam * nie ma * jednego wspólnego interfejsu. Jednak istnieją oddzielne biblioteki, dlatego zacytowałem FastMember. –

+1

Naprawdę chciałbym zaznaczyć zarówno @CrazyCasta i marc jako odpowiedzi, ponieważ są one pomocne, ale ostatecznie poszedłem z MemberInfo przy użyciu metod rozszerzenia. – Timmerz

10

Zwrot rodzaje GetProperties() i GetFields() są różne, jak to wydaje się, że nie zauważył. Trzeba będzie zdefiniować interfejs za pomocą GetValue() i SetValue() i użyć rozszerzenia ParameterInfo i FieldInfo do implementacji tego interfejsu. To prawdopodobnie pracować jako owijki:

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

to pozwoli Ci zrobić GetType().GetParametersAndFields() (tj użyć standardowych typów odbicia).

+3

'MemberInfo'; p –

+4

@MarcGravell To nie ma metod pobierania i ustawiania. – CrazyCasta

2

Korzystanie DLR (dość proste, jeśli znasz nazwę użytkownika w czasie kompilacji):

((dynamic)obj).MyFieldOrPropertyName = myValue; 

Jeśli tylko znać nazwę użytkownika w czasie wykonywania, polecam FastMember, jak Marc Gravell zasugerował.

6

Trochę późno, ale wpadłem na następujący ... 1 pętli działa jak czar ;-)

 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

Aby uzyskać albo właściwości lub pola, można powiedzieć:

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

gdzie bindingAttr może być

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

Usuń BindingFlags.NonPublic jeśli nie chce się non-PU członków blic. Nawiasem mówiąc, zapytanie nie jest pojedynczą instrukcją, ale pojedynczym oświadczenie.


Aby uzyskać wartość obu nieruchomości lub polu bez rzucania go przez siebie, wykorzystywać InvokeMember do 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); 
} 

Podobnie, aby ustawić wartość:

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

Wyrzuci, jeśli jako pierwszy argument zostanie przekazany MemberInfo inny niż PropertyInfo lub FieldInfo, ponieważ BindingFlags.Default nie robi " t określić, co zamierzasz zrobić.

Powiązane problemy