FastDelegate via Lambda Expression
A cosa serve in realtà? serve in tutti quegli scenari in cui dovete chiamare n volte un metodo via reflection (o simili), okkio che ho detto n volte perchè anche la chiamata al metodo Compile() della Lambda Expression ha un costo ma una volta fatta avete in mano qualcosa di “cachabile” e quindi dalla seconda chiamata in poi vi “leccate le orecchie” :-)public delegate object LateBoundMethod( object target, object[] arguments ); public static class DelegateFactory { public static LateBoundMethod CreateDelegate( this MethodInfo method ) { var instanceParameter = Expression.Parameter( typeof( object ), "target" ); var argumentsParameter = Expression.Parameter( typeof( object[] ), "arguments" ); var call = CreateMethodCallExpression( method, instanceParameter, argumentsParameter ); var lambda = Expression.Lambda<LateBoundMethod>( Expression.Convert( call, typeof( object ) ), instanceParameter, argumentsParameter ); return lambda.Compile(); } private static MethodCallExpression CreateMethodCallExpression( MethodInfo method, ParameterExpression instanceParameter, ParameterExpression argumentsParameter ) { var call = Expression.Call( Expression.Convert( instanceParameter, method.DeclaringType ), method, CreateParameterExpressions( method, argumentsParameter ) ); return call; } private static Expression[] CreateParameterExpressions( MethodInfo method, Expression argumentsParameter ) { return method.GetParameters().Select( ( parameter, index ) => Expression.Convert( Expression.ArrayIndex( argumentsParameter, Expression.Constant( index ) ), parameter.ParameterType ) ).ToArray(); } }
Altra nota da redazione, quella cosa si schianta immedatamente (con una Exception decisamente poco comunicativa) se state cercando di creare un “fast delegate” per un metodo “void”:
è decisamente uguale a quella di prima… ma la firma del delegato deve rispettare il fatto che il target method sia void.public delegate void LateBoundVoidMethod( object target, object[] arguments ); public static class DelegateFactory { public static LateBoundVoidMethod CreateVoidDelegate( this MethodInfo method ) { var instanceParameter = Expression.Parameter( typeof( object ), "target" ); var argumentsParameter = Expression.Parameter( typeof( object[] ), "arguments" ); var call = CreateMethodCallExpression( method, instanceParameter, argumentsParameter ); var lambda = Expression.Lambda<LateBoundVoidMethod>( call, instanceParameter, argumentsParameter ); return lambda.Compile(); } }
.m