Nuestro equipo de expertos pasados varios días de investigación y recopilar de datos, obtuvieron la respuesta, deseamos que resulte de utilidad para tu trabajo.
Solución:
Con respecto a llamar a un método:
- La llamada directa es inmejorable en cuanto a velocidad.
-
Usar Expression API es globalmente similar a usar
Reflection.Emit
oDelegate.CreateDelegate
en cuanto a la velocidad (se pueden medir pequeñas diferencias; como siempre, optimizar la velocidad sin mediciones y objetivos es inútil).Todos generan IL y el marco lo compilará en código nativo en algún momento. Pero aún paga el costo de un nivel de indirección para llamar al delegado y una llamada de método dentro de su delegado.
La expresión API es más limitada, pero un orden de magnitud más simple de usar, ya que no requiere que aprenda IL.
-
Dynamic Language Runtime se usa directamente o a través del
dynamic
La palabra clave de C# 4 agrega un poco de sobrecarga pero permanece cerca de la emisión de código, ya que almacena en caché la mayoría de las comprobaciones relacionadas con los tipos de parámetros, el acceso y el resto.Cuando se utiliza a través de la
dynamic
palabra clave también obtiene la sintaxis más ordenada, ya que parece una llamada de método normal. Pero si usa dinámica, está limitado a las llamadas a métodos, mientras que la biblioteca puede hacer mucho más (consulte IronPython) System.Reflection.MethodInfo.Invoke
es lento: además de qué otros métodos necesita para verificar los derechos de acceso, verificar el recuento de argumentos, el tipo, … contra elMethodInfo
cada vez que llame al método.
Jon Skeet también obtuvo algunos buenos puntos en esta respuesta: Delegate.CreateDelegate vs DynamicMethod vs Expression
Algunas muestras, lo mismo hecho de diferentes maneras.
A partir del número de líneas y la complejidad, ya puede ver qué soluciones son fáciles de mantener y cuáles deben evitarse desde el punto de vista del mantenimiento a largo plazo.
La mayoría de los ejemplos no tienen sentido, pero demuestran las clases/sintaxis básicas de generación de código de C#, para obtener más información, siempre está el MSDN
PD: Dump es un método LINQPad.
public class Foo
public string Bar(int value) return value.ToString();
void Main()
object foo = new Foo();
// We have an instance of something and want to call a method with this signature on it :
// public string Bar(int value);
Console.WriteLine("Cast and Direct method call");
var result = ((Foo)foo).Bar(42);
result.Dump();
Console.WriteLine("Create a lambda closing on the local scope.");
// Useless but i'll do it at the end by manual il generation
Func func = i => ((Foo)foo).Bar(i);
var result = func(42);
result.Dump();
Console.WriteLine("Using MethodInfo.Invoke");
var method = foo.GetType().GetMethod("Bar");
var result = (string)method.Invoke(foo, new object[] 42 );
result.Dump();
Console.WriteLine("Using the dynamic keyword");
var dynamicFoo = (dynamic)foo;
var result = (string)dynamicFoo.Bar(42);
result.Dump();
Console.WriteLine("Using CreateDelegate");
var method = foo.GetType().GetMethod("Bar");
var func = (Func)Delegate.CreateDelegate(typeof(Func), foo, method);
var result = func(42);
result.Dump();
Console.WriteLine("Create an expression and compile it to call the delegate on one instance.");
var method = foo.GetType().GetMethod("Bar");
var thisParam = Expression.Constant(foo);
var valueParam = Expression.Parameter(typeof(int), "value");
var call = Expression.Call(thisParam, method, valueParam);
var lambda = Expression.Lambda>(call, valueParam);
var func = lambda.Compile();
var result = func(42);
result.Dump();
Console.WriteLine("Create an expression and compile it to a delegate that could be called on any instance.");
// Note that in this case "Foo" must be known at compile time, obviously in this case you want
// to do more than call a method, otherwise just call it !
var type = foo.GetType();
var method = type.GetMethod("Bar");
var thisParam = Expression.Parameter(type, "this");
var valueParam = Expression.Parameter(typeof(int), "value");
var call = Expression.Call(thisParam, method, valueParam);
var lambda = Expression.Lambda>(call, thisParam, valueParam);
var func = lambda.Compile();
var result = func((Foo)foo, 42);
result.Dump();
Console.WriteLine("Create a DynamicMethod and compile it to a delegate that could be called on any instance.");
// Same thing as the previous expression sample. Foo need to be known at compile time and need
// to be provided to the delegate.
var type = foo.GetType();
var method = type.GetMethod("Bar");
var dynamicMethod = new DynamicMethod("Bar_", typeof(string), new [] typeof(Foo), typeof(int) , true);
var il = dynamicMethod.GetILGenerator();
il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Ret);
var func = (Func)dynamicMethod.CreateDelegate(typeof(Func));
var result = func((Foo)foo, 42);
result.Dump();
Console.WriteLine("Simulate closure without closures and in a lot more lines...");
TypeAttributes.Public);
var fooField = tb.DefineField("FooInstance", type, FieldAttributes.Public);
var barMethod = tb.DefineMethod("Bar_", MethodAttributes.Public, typeof(string), new [] typeof(int) );
var il = barMethod.GetILGenerator();
il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldfld, fooField);
il.Emit(OpCodes.Ldarg_1); // arg
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Ret);
var closureType = tb.CreateType();
var instance = closureType.GetConstructors().Single().Invoke(new object[0]);
closureType.GetField(fooField.Name).SetValue(instance, foo);
var methodOnClosureType = closureType.GetMethod("Bar_");
var func = (Func)Delegate.CreateDelegate(typeof(Func), instance,
closureType.GetMethod("Bar_"));
var result = func(42);
result.Dump();
La reflexión funciona más lentamente. Para un buen artículo sobre esto ver este artículo.
Este tipo realmente lo midió.
http://www.palmmedia.de/Blog/2012/2/4/reflection-vs-compiled-expressions-vs-delegates-performance-comparison
En resumen: expresión compilada que es en caché a un static var y reutilizado: funciona mucho más rápido que la reflexión.
Eres capaz de añadir valor a nuestro contenido asistiendo con tu experiencia en las interpretaciones.