dynamic - Expression and delegate in c# -
i have below code pseudo-code. want make function can accept expresstion type, compile expression , invoke proper parameters.
public static void f<t>(expression<t> exp, params dynamic[] d) { console.writeline("begin"); exp.compile().invoke(d[0],d[1].....);//this pseudo-code console.writeline("end"); }
i'm sure t action type. (t can action
,action<int>
,etc.). parameter d
array of dynamic type, sent invoke.
but don't know how finish code. i'm sure that's not easy implement it. perhaps can't true in c#
you can't use invoke
unless know exact signature. can, however, use dynamicinvoke
, example:
((delegate)exp.compile()).dynamicinvoke(d);
note dynamic
in above serves no purpose - d
object[]
.
the other, more complicated, approach - compile func<object[]>
, , re-write expression (expressionvisitor
) replace "parameter n" (from original exp
) p[n]
, p
single parameterexpression
, n
constantexpression
of n
. might advantageous if going store , aggressively re-use compiled lambda. in specific scenario compiling per call, have no benefit.
here's example, intended later readers similar scenarios, compiled delegate re-used; "advantage" of re-writing avoids performance impact of delegate.dynamicinvoke
, while retaining object[] => object
signature of delegate.dynamicinvoke
; useful if delegate being used multiple times. @ moment (compiled per call) of "work" here going in expression-compile , jit-compile.
using system; using system.collections.generic; using system.linq.expressions; static class program { static void main() { expression<func<int, float, double>> exp = (i, f) => * f; var func = compiletobasictype(exp); object[] args = { 3, 2.3f }; object result = func(args); // 6.9 (double) } static func<object[], object> compiletobasictype(lambdaexpression exp) { parameterexpression arg = expression.parameter(typeof(object[]), "args"); dictionary<expression, expression> lookup = new dictionary<expression, expression>(); int = 0; foreach (var p in exp.parameters) { lookup.add(p, expression.convert(expression.arrayindex( arg, expression.constant(i++)), p.type)); } var body = expression.convert( new replacevisitor(lookup).visit(exp.body), typeof(object)); return expression.lambda<func<object[], object>>(body, arg).compile(); } class replacevisitor : expressionvisitor { private readonly dictionary<expression, expression> lookup; public replacevisitor(dictionary<expression, expression> lookup) { if (lookup == null) throw new argumentnullexception("lookup"); this.lookup= lookup; } public override expression visit(expression node) { expression found; return lookup.trygetvalue(node, out found) ? found : base.visit(node); } } }
Comments
Post a Comment