如何通过reflection在单个调用中获取字段和属性?

如果在某处覆盖,我道歉。 我在发布前做过研究!

好吧,所以问题……我正在使用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"); } } 

怎么样:

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

或者,像FastMember这样的库可以很好地使用字段或属性,无论成员类型如何,get / set都是相同的。

正如您似乎注意到的那样,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 retList = new List(); 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() (即使用标准reflection类型)。

有点晚了,但我想出了以下…… 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); } } 

要获得属性或字段,您可以说:

 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 。 顺便说一句,查询不是单个调用,而是单个语句


要获取属性或字段的值而不InvokeMember强制转换,请使用InvokeMember作为技巧:

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

如果您传递除PropertyInfoFieldInfo之外的MemberInfo作为第一个参数,它将抛出,因为BindingFlags.Default没有指定您要执行的操作。

使用DLR(如果您在编译时知道成员名称,那么就够了):

 ((dynamic)obj).MyFieldOrPropertyName = myValue; 

如果您在运行时只知道成员名称,我建议使用FastMember ,正如Marc Gravell建议的那样。