Creo que sería mejor que CreateDelegate
construir si el rendimiento es la clave. Dado que conoce la firma del método de antemano, que aquí es solo GetGetMethod
y GetSetMethod
del PropertyInfo
, puede crear un delegado para ejecutar directamente el mismo método con la misma firma. Las expresiones serían más adecuadas si necesita construir alguna lógica (para la cual no tenía un método maneja) para los delegados.He hecho un poco de evaluación comparativa de las diferentes rutas a este problema:
Func<S, T> Getter;
Action<S, T> Setter;
PropertyInfo Property;
public void Initialize(Expression<Func<S, T>> propertySelector)
{
var body = propertySelector.Body as MemberExpression;
if (body == null)
throw new MissingMemberException("something went wrong");
Property = body.Member as PropertyInfo;
//approaches:
//Getter = s => (T)Property.GetValue(s, null);
//Getter = memberSelector.Compile();
//ParameterExpression inst = Expression.Parameter(typeof(S));
//Getter = Expression.Lambda<Func<S, T>>(Expression.Property(inst, Property), inst).Compile();
//var inst = Expression.Parameter(typeof(S));
//Getter = Expression.Lambda<Func<S, T>>(Expression.Call(inst, Property.GetGetMethod()), inst).Compile();
//Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), Property.GetGetMethod());
//Setter = (s, t) => Property.SetValue(s, t, null);
//var val = Expression.Parameter(typeof(T));
//var inst = Expression.Parameter(typeof(S));
//Setter = Expression.Lambda<Action<S, T>>(Expression.Call(inst, Property.GetSetMethod(), val),
// inst, val).Compile();
//Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), Property.GetSetMethod());
}
//Actual calls (tested under loop):
public T Get(S instance)
{
//direct invocation:
//return (T)Property.GetValue(instance, null);
//calling the delegate:
//return Getter(instance);
}
public void Set(S instance, T value)
{
//direct invocation:
//Property.SetValue(instance, value, null);
//calling the delegate:
//Setter(instance, value);
}
Resultados para unos 10 millones de llamadas - (Get, Set):
GetValue-SetValue (directa): 3800 m, 5500 ms
GetValue-FijarValor (delegado): 3600 ms, 5300 ms
expresiones compilados:
Get: Expression.Property: 280 ms
Expression.Call: 280 ms
direct compile: 280 ms
Set: 300 ms
crear delegado: 130 ms, 135 ms
llamada propiedad directa: 70 ms, 70 ms
lo haría, en su caso, escriba:
public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>();
}
public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector)
{
return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>();
}
// a generic extension for CreateDelegate
public static T CreateDelegate<T>(this MethodInfo method) where T : class
{
return Delegate.CreateDelegate(typeof(T), method) as T;
}
public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector)
{
var body = propertySelector.Body as MemberExpression;
if (body == null)
throw new MissingMemberException("something went wrong");
return body.Member as PropertyInfo;
}
Así que ahora usted llama:
TestClass cwp = new TestClass();
var access = BuildGetAccessor((TestClass t) => t.AnyValue);
var result = access(cwp);
No es eso simpl er? Había escrito una clase genérica here para manejar la situación exacta.
"Lo estoy haciendo porque no puedo usar métodos con" < T > "debido a la estructura de mi aplicación" - ¿Eso significa su versión de NETFX <2.0? ¿Por qué no puedes usar genéricos en tu aplicación? –
Además, ¿qué tiene que ver la creación de delegados para sus propiedades con la reflexión y qué problema está tratando de resolver mediante la reflexión? –
Los delegados tienen un rendimiento mucho mejor y se pueden usar dinámicamente. Son la opción preferida cuando necesita usar una invocación dinámica. – GregRos