public void GetInvokeMethodWorks() { Assert.Equal(typeof(string), MethodInfoEx.GetInvokeMethod(typeof(Func <string>)).ReturnType); Assert.Equal(0, MethodInfoEx.GetInvokeMethod(typeof(Func <string>)).GetParameters().Length); Assert.Equal(typeof(void), MethodInfoEx.GetInvokeMethod(typeof(Action <string, string>)).ReturnType); Assert.Equal(2, MethodInfoEx.GetInvokeMethod(typeof(Action <string, string>)).GetParameters().Length); Assert.Throws <ArgumentException>(() => MethodInfoEx.GetInvokeMethod(typeof(string))); Assert.Throws <ArgumentException>(() => MethodInfoEx.GetInvokeMethod(typeof(ClassWithInvoke))); }
private static DynamicMethod BuildInvoke() { var invokeMethod = MethodInfoEx.GetInvokeMethod(typeof(T)); var parameters = invokeMethod.GetParameters(); var args = new Type[parameters.Length + 1]; args[0] = typeof(WeakDelegate <T>); for (var i = 0; i < parameters.Length; i++) { args[i + 1] = parameters[i].ParameterType; } var returnType = invokeMethod.ReturnType; var invoke = new DynamicMethod(string.Empty, returnType, args, typeof(WeakDelegate <T>).Module, MemberInfoEx.PrivateAccess); var il = invoke.GetILGenerator(); //var del = il.DeclareLocal(typeof(T)); var hasReturn = returnType != typeof(void); var returnValue = hasReturn ? il.DeclareLocal(returnType) : null; // get enumerator il.Emit(OpCodes.Ldarg_0); il.EmitForEach(typeof(IEnumerable <T>), l => { for (var i = 1; i < args.Length; i++) { il.EmitLdarg(i); } il.EmitCall(OpCodes.Callvirt, invokeMethod, null); if (hasReturn) { il.EmitStloc(returnValue); } }); if (hasReturn) { il.EmitLdloc(returnValue); } il.Emit(OpCodes.Ret); return(invoke); }
static ExpressionsImpl() { var invokeMethod = MethodInfoEx.GetInvokeMethod(typeof(T)); _invokeParameters = invokeMethod.GetParameters() .ConvertAll((x, i) => Expression.Parameter(x.ParameterType, "p" + i)); _getEnumerator = typeof(IEnumerable <T>).Method("GetEnumerator"); _enumerator = Expression.Variable(typeof(IEnumerator <T>), "e"); var destroyEnumerator = Expression.Call(_enumerator, typeof(IDisposable).Method("Dispose")); var returnType = invokeMethod.ReturnType; var hasReturn = returnType != typeof(void); var breakLabel = hasReturn ? Expression.Label(returnType, "br") : Expression.Label("br"); var result = hasReturn ? Expression.Variable(returnType, "r") : null; var breakExpr = hasReturn ? Expression.Break(breakLabel, result) : Expression.Break(breakLabel); var moveNext = Expression.Call(_enumerator, typeof(IEnumerator).Method("MoveNext")); var current = Expression.Property(_enumerator, typeof(IEnumerator <T>).Property("Current")); // ReSharper disable once CoVariantArrayConversion var invoke = (Expression)Expression.Invoke(current, _invokeParameters); if (hasReturn) { invoke = Expression.Assign(result, invoke); } var ifNotMoveNext = Expression.IfThenElse(moveNext, invoke, breakExpr); var loop = (Expression)Expression.Loop(ifNotMoveNext, breakLabel); if (hasReturn) { loop = Expression.Block(new[] { result }, Expression.Assign(result, Expression.Default(returnType)), loop); } _invokeLoop = Expression.TryFinally(loop, destroyEnumerator); }
/// <summary> /// Creates dynamic method that matches delegateType /// </summary> public static DynamicMethod CreateMethod(this Type owner, Type delegateType, string name = null, bool skipVisibility = false) { var invoke = MethodInfoEx.GetInvokeMethod(delegateType); return(new DynamicMethod(name ?? string.Empty, invoke.ReturnType, invoke.GetParameterTypes(), owner, skipVisibility)); }
/// <summary> /// Creates dynamic method that matches delegateType /// </summary> public static DynamicMethod CreateMethod(this Module m, Type delegateType, string name, bool skipVisibility = false) { var invoke = MethodInfoEx.GetInvokeMethod(delegateType); return(new DynamicMethod(name, invoke.ReturnType, invoke.GetParameterTypes(), m, skipVisibility)); }
/// <summary> /// Converts lambda input and return types /// </summary> /// <param name="lambda">lambda to convert</param> /// <param name="delegateType">new delegate type</param> /// <returns></returns> public static LambdaExpression Convert(LambdaExpression lambda, Type delegateType) { if (lambda.Type == delegateType) { return(lambda); } var invoke = MethodInfoEx.GetInvokeMethod(delegateType); var result = invoke.ReturnType; var invokeParameters = invoke.GetParameters(); var parameters = invokeParameters.ConvertAll(p => p.ParameterType); if (parameters.Length < lambda.Parameters.Count) { throw new ArgumentException("Parameters count is less than lambdas", nameof(delegateType)); } if (SignatureMatch(lambda, result, parameters)) { // Fixes stupid issue in .Net framework - byref delegates are not convertible, so can't compile byref =\ return(delegateType == null ? lambda : Expression.Lambda(delegateType, lambda.Body, lambda.Parameters)); } var newParameters = parameters.ConvertAll(Expression.Parameter); var variables = new List <ParameterExpression>(); var inConversions = new List <Expression>(); var outConversions = new List <Expression>(); var call = new Expression[lambda.Parameters.Count]; for (var i = 0; i < lambda.Parameters.Count; i++) { var lambdaParam = lambda.Parameters[i]; var newParam = newParameters[i]; if (lambdaParam.Type == newParam.Type) { // no conversion call[i] = newParam; continue; } if (!(newParam.IsByRef && lambdaParam.IsByRef)) { //call[i] = newParam.TypeAs(lambdaParam.Type); call[i] = newParam.Convert(lambdaParam.Type); continue; } var variable = Expression.Variable(lambdaParam.Type); call[i] = variable; variables.Add(variable); inConversions.Add(invokeParameters[i].IsOut ? variable.Assign(Expression.Default(lambdaParam.Type)) : variable.Assign(newParam.Convert(lambdaParam.Type))); outConversions.Add(newParam.Assign(variable.Convert(newParam.Type))); } var newBody = Inline(lambda, call); if (variables.Count == 0) { if (result == newBody.Type) { return(Expression.Lambda(delegateType, newBody, newParameters)); } if (result == typeof(void) || newBody.Type == typeof(void)) { newBody = Expression.Block(newBody, Expression.Default(result)); } else { newBody = newBody.Convert(result); } } else { if (result == typeof(void) || newBody.Type == typeof(void)) { outConversions.Add(Expression.Default(result)); } else { var resultVariable = Expression.Variable(result); newBody = Expression.Assign(resultVariable, newBody.Convert(result)); variables.Add(resultVariable); outConversions.Add(resultVariable); } inConversions.Add(newBody); newBody = Expression.Block(variables, inConversions.Concat(outConversions)); } return(Expression.Lambda(delegateType, newBody, newParameters)); }