c# - property - ¿Cómo obtener ambos campos y propiedades en una sola llamada a través de la reflexión?
propertyinfo c# (5)
Los tipos de devolución de GetProperties () y GetFields () son diferentes, como parece haber notado. Tendría que definir una interfaz con GetValue () y SetValue () y usar extend ParameterInfo y FieldInfo para implementar esta interfaz. Esto probablemente funcionaría como una envoltura:
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();
}
}
Esto le permitirá hacer GetType().GetParametersAndFields()
(es decir, usar los tipos de reflexión estándar).
Pido disculpas si esto está cubierto en alguna parte. Hice una investigación antes de publicar!
Bueno, pregunta ... estoy usando GetType () .GetProperties, pero no está devolviendo campos de instancia simples, que no tienen get / set en ellos ... así que usé .GetFields, que los encuentra pero quiero obtener un solo objeto simple para obtener / establecer un valor sin cambiar entre campos y propiedades ... ¿es esto posible?
mi código actual funciona en PropertyInfo, que funciona muy bien, pero eso no es para campos, supongo.
[edit] esta es la solución que se me ocurrió, que funciona bien. gracias a todos....
// 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");
}
}
Para obtener propiedades o campos, puedes decir:
var q=
from it in type.GetMembers(bindingAttr)
where it is PropertyInfo||it is FieldInfo
select it;
donde bindingAttr
podría ser
var bindingAttr=
BindingFlags.NonPublic|
BindingFlags.Public|
BindingFlags.Instance;
Elimine BindingFlags.NonPublic
si no desea obtener miembros no públicos. Por cierto, la consulta no es una sola llamada sino una sola declaración .
Para obtener el valor de una propiedad o un campo sin tener que InvokeMember
usted mismo, use InvokeMember
para el truco:
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);
}
Del mismo modo, para establecer el valor:
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);
}
Se lanzará si pasa un MemberInfo
no sea PropertyInfo
o FieldInfo
como primer argumento, porque BindingFlags.Default
no especifica lo que va a hacer.
Qué tal si:
const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
MemberInfo[] members = type.GetFields(bindingFlags).Cast<MemberInfo>()
.Concat(type.GetProperties(bindingFlags)).ToArray();
Alternativamente, las bibliotecas como FastMember trabajarán felizmente con los campos o las propiedades, con get / set idéntico sin importar el tipo de miembro.
Un poco tarde, pero se me ocurrió lo siguiente ... 1 bucle, funciona como un encanto ;-)
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);
}
}
Uso de DLR (lo suficientemente simple, si conoce el nombre del miembro en tiempo de compilación):
((dynamic)obj).MyFieldOrPropertyName = myValue;
Si solo conoce el nombre del miembro en tiempo de ejecución , recomendaría FastMember , como sugirió Marc Gravell.