.net - In C#, Is Expression API better than Reflection -
nowadays, i'm exploring c# expression apis. use understanding how works, including difference between expression , reflection. want understand if expressions merely syntactic sugar, or indeed better reflection performance-wise?
good examples links articles appreciated. :-)
regarding calling 1 method :
- direct call can't beaten speed-wise.
using expression api globally similar using
reflection.emit
ordelegate.createdelegate
speed-wise (small differences measured; optimizing speed without measurements , goals useless).they generate il , framework compile native code @ point. still pay cost of 1 indirection level calling delegate , 1 method call inside delegate.
the expression api more limited, order of magnitude simpler use, doesn't require learn il.
the dynamic language runtime either used directly or via
dynamic
keyword of c# 4 add little overhead stay near emitting code cache checks related parameter types, access , rest.when used via
dynamic
keyword it's neatest syntax looks normal method call. if use dynamic limited method calls while library able lot more (see ironpython)system.reflection.methodinfo.invoke
slow : in addition other methods need check access rights, check arguments count, type, ... againstmethodinfo
each time call method.
jon skeet points in answer : delegate.createdelegate vs dynamicmethod vs expression
some samples, same thing done different ways.
you see line count , complexity solutions easy maintain , should avoided long term maintenance standpoint.
most of samples pointless demonstrate basic code generation classes / syntaxes of c#, more info there msdn
ps: dump linqpad method.
public class foo { public string bar(int value) { return value.tostring(); } } void main() { object foo = new foo(); // have instance of , want call method signature on : // public string bar(int value); console.writeline("cast , direct method call"); { var result = ((foo)foo).bar(42); result.dump(); } console.writeline("create lambda closing on local scope."); { // useless i'll @ end manual il generation func<int, string> func = => ((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 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<int, string>)delegate.createdelegate(typeof(func<int, string>), foo, method); var result = func(42); result.dump(); } console.writeline("create expression , compile call delegate on 1 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<func<int, string>>(call, valueparam); var func = lambda.compile(); var result = func(42); result.dump(); } console.writeline("create expression , compile delegate called on instance."); { // note in case "foo" must known @ compile time, in case want // more call method, otherwise call ! 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<func<foo, int, string>>(call, thisparam, valueparam); var func = lambda.compile(); var result = func((foo)foo, 42); result.dump(); } console.writeline("create dynamicmethod , compile delegate called on instance."); { // same thing previous expression sample. foo need known @ compile time , need // provided 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<foo, int, string>)dynamicmethod.createdelegate(typeof(func<foo, int, string>)); var result = func((foo)foo, 42); result.dump(); } console.writeline("simulate closure without closures , in lot more lines..."); { var type = foo.gettype(); var method = type.getmethod("bar"); // foo class must public work, "skipvisibility" argument of // dynamicmethod.createdelegate can't emulated without breaking .net security model. var assembly = appdomain.currentdomain.definedynamicassembly( new assemblyname("myassembly"), assemblybuilderaccess.run); var module = assembly.definedynamicmodule("mymodule"); var tb = module.definetype("mytype", typeattributes.class | 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); // 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<int, string>)delegate.createdelegate(typeof(func<int, string>), instance, closuretype.getmethod("bar_")); var result = func(42); result.dump(); } }
Comments
Post a Comment