usar porque los funcionan funcion delegate delegados delegado como c# reflection action expression setvalue

porque - Rendimiento de reflexión: Crear delegado(Propiedades C#)



funcion delegado c# (3)

Estoy teniendo problemas de rendimiento con el uso de la reflexión.
Así que decidí crear delegados para las propiedades de mis objetos y hasta ahora obtuve esto:

TestClass cwp = new TestClass(); var propertyInt = typeof(TestClass).GetProperties().Single(obj => obj.Name == "AnyValue"); var access = BuildGetAccessor(propertyInt.GetGetMethod()); var result = access(cwp);

static Func<object, object> BuildGetAccessor(MethodInfo method) { var obj = Expression.Parameter(typeof(object), "o"); Expression<Func<object, object>> expr = Expression.Lambda<Func<object, object>>( Expression.Convert( Expression.Call( Expression.Convert(obj, method.DeclaringType), method), typeof(object)), obj); return expr.Compile(); }

Los resultados fueron altamente satisfactorios, aproximadamente 30-40 veces más rápidos que con el método convencional ( PropertyInfo.GetValue (obj, null); )

El problema es: ¿cómo puedo hacer un SetValue de una propiedad, que funciona de la misma manera? Lamentablemente, no obtuve una manera.

Lo estoy haciendo porque no puedo usar métodos con <T> debido a la estructura de mi aplicación.


Creo que estaría mejor con la construcción CreateDelegate si el rendimiento es la clave. Como conoce la firma del método de antemano, que aquí es solo GetGetMethod y GetSetMethod de 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. Hice algunos benchmarking en 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 de aproximadamente 10000000 llamadas - (Obtener, establecer):

GetValue-SetValue (directo): 3800 ms, 5500 ms

GetValue-SetValue (delegar): 3600 ms, 5300 ms

expresiones compiladas:

Get: Expression.Property: 280 ms Expression.Call: 280 ms direct compile: 280 ms Set: 300 ms

crear delegado: 130 ms, 135 ms

llamada de propiedad directa: 70 ms, 70 ms

Yo, en tu caso, escribiría:

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

Entonces ahora llamas:

TestClass cwp = new TestClass(); var access = BuildGetAccessor((TestClass t) => t.AnyValue); var result = access(cwp);

¿No es eso más simple? Había escrito una clase genérica here para manejar la cosa exacta.


Esto debería funcionar para usted:

static Action<object, object> BuildSetAccessor(MethodInfo method) { var obj = Expression.Parameter(typeof(object), "o"); var value = Expression.Parameter(typeof(object)); Expression<Action<object, object>> expr = Expression.Lambda<Action<object, object>>( Expression.Call( Expression.Convert(obj, method.DeclaringType), method, Expression.Convert(value, method.GetParameters()[0].ParameterType)), obj, value); return expr.Compile(); }

Uso:

var accessor = BuildSetAccessor(typeof(TestClass).GetProperty("MyProperty").GetSetMethod()); var instance = new TestClass(); accessor(instance, "foo"); Console.WriteLine(instance.MyProperty);

Con TestClass :

public class TestClass { public string MyProperty { get; set; } }

Imprime:

foo


Utiliza tipos dinámicos. Usan reflejo debajo del capó, pero son mucho más rápidos.

De otra manera...

Hay toneladas de bibliotecas de reflexión gratuitas más rápidas con licencias permisivas. Te vincularía, pero hay demasiados, y no estoy seguro de cuál te conviene. Simplemente busque codeplex, etc. Cuando encuentre algo que le guste, pruébelo.

Pero sí, quizás antes de eso, piense si la reflexión realmente es la respuesta. A menudo hay otras soluciones.

Editar: según lo solicitado ...

http://geekswithblogs.net/SunnyCoder/archive/2009/06/26/c-4.0-dynamics-vs.-reflection.aspx
http://theburningmonk.com/2010/09/performance-test-dynamic-method-invocation-in-csharp-4/
http://www.mssoftwareconsulting.com/msswc/blog/post/C-40-and-dynamic-performance.aspx

Es un conocimiento común por lo que puedo decir.