2012-10-01 21 views
19

如果覆蓋某處,我很抱歉。我在發佈前做過調查!如何通過反射在單個調用中獲取字段和屬性?

好吧,所以問題...我使用GetType().GetProperties,但它沒有返回簡單的實例字段,它們沒有get/set對他們...所以我用.GetFields,找到它們,但我想獲得一個簡單的單個對象來獲取/設置一個值,而不需要在字段和屬性之間進行翻轉......這可能嗎?

我目前的代碼在PropertyInfo上工作,這是工作很好,但這不是我猜的字段?

這是我想出的解決方案,這是行之有效的。感謝大家....

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

回答

22

如何:

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

可替代地,像FastMember庫將愉快地字段或屬性的作用,以獲取/設置相同而不管構件型的。

+0

從OP:「得到一個簡單的單一對象來獲取/設置值」。我不確定MemberInfo是如何做到這一點的。 – CrazyCasta

+1

@CrazyCasta確實;如果你想,你需要爲有核心的反射API外臺階*爲*的,沒有一個單一的共享接口。然而,單獨的庫確實存在,這就是我引用FastMember的原因。 –

+1

我真的想都@CrazyCasta和Marc標記爲答案,因爲他們都是有幫助的,但最終我沒有用的MemberInfo使用擴展方法去。 – Timmerz

10

的返回類型的GetProperties()和GetFields()是不同的,因爲你似乎已經注意到了。您必須使用GetValue()和SetValue()定義接口,並使用擴展ParameterInfo和FieldInfo來實現此接口。這可能會工作作爲包裝:

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

這將允許你這樣做GetType().GetParametersAndFields()(即使用標準的反射類型)。

+3

'MemberInfo',P –

+4

@MarcGravell不具有get和set方法。 – CrazyCasta

2

使用DLR(很簡單,如果你知道在編譯時的成員名):

​​

如果你只知道在運行時成員的名字,我會建議FastMember,如馬克· Gravell建議。

6

有點晚了,但我想出了下面...... 1環,就像一個魅力;-)

 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

爲了獲得無論是性能或字段,你可以說:

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

其中bindingAttr可能是

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

刪除BindingFlags.NonPublic,如果你不想讓非普blic成員。順便說一句,查詢不是一個單獨的調用而是單個陳述


要獲得可以是屬性或字段的值,而自己鑄造它,使用InvokeMember用於特技:

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

同樣,設定值:

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

如果傳遞MemberInfo以外PropertyInfoFieldInfo作爲第一個參數,則會引發,因爲沒有按BindingFlags.Default」不要指定你要做什麼。

相關問題