Как получить оба поля и свойства в одном вызове через отражение?
Извиняюсь, если это где-то покрыто. Я занимался исследованиями до публикации!
в порядке, так что вопрос... Я использую GetType().GetProperties, но он не возвращает простые поля экземпляра, которые не имеют/устанавливают на них... поэтому я использовал .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");
}
}
Ответы
Ответ 1
Как насчет:
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
MemberInfo[] members = type.GetFields(bindingFlags).Cast<MemberInfo>()
.Concat(type.GetProperties(bindingFlags)).ToArray();
В качестве альтернативы библиотеки, такие как FastMember, будут работать с любыми полями или свойствами, причем get/set идентичны независимо от типа члена.
Ответ 2
Возвращаемые типы 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
Немного поздно, но я придумал следующий цикл: 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);
}
}
Ответ 4
Чтобы получить свойства или поля, вы можете сказать:
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
для трюка:
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
, кроме PropertyInfo
или FieldInfo
в качестве первого аргумента, потому что BindingFlags.Default
не указывает, что вы собираетесь делать.
Ответ 5
Использование DLR (достаточно просто, если вы знаете имя участника во время компиляции):
((dynamic)obj).MyFieldOrPropertyName = myValue;
Если вы знаете только имя участника во время выполнения, я бы рекомендовал FastMember, как предложил Марк Гравелл.