public static void EmitCast(this ILGenerator g, Type from, Type to) { if (from == to) { return; } if (to == typeof(object)) { g.EmitBox(from); } else if (from == typeof(object)) { g.EmitUnBoxAnyOrCastClass(to); } else { var method = MethodInfoEx.FindCastOperator(from, to); if (method != null) { g.EmitMethodCall(method); } else if (!to.IsAssignableFrom(from)) { g.Emit(OpCodes.Castclass, to); } } }
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))); }
public void FindCastFromWorks() { var t = typeof(Cast2); Assert.Equal(typeof(int), MethodInfoEx.FindCastFromOperator(typeof(int), t).GetParameterTypes()[0]); Assert.Equal(typeof(double), MethodInfoEx.FindCastFromOperator(typeof(double), t).GetParameterTypes()[0]); Assert.Equal(typeof(Cast1), MethodInfoEx.FindCastFromOperator(typeof(Cast1), t).GetParameterTypes()[0]); Assert.Null(MethodInfoEx.FindCastFromOperator(typeof(string), t)); Assert.Null(MethodInfoEx.FindCastFromOperator(typeof(decimal), t)); }
public void FindCastToWorks() { var t = typeof(Cast1); Assert.Equal(typeof(int), MethodInfoEx.FindCastToOperator(t, typeof(int)).ReturnType); Assert.Equal(typeof(double), MethodInfoEx.FindCastToOperator(t, typeof(double)).ReturnType); Assert.Equal(typeof(Cast2), MethodInfoEx.FindCastToOperator(t, typeof(Cast2)).ReturnType); Assert.Null(MethodInfoEx.FindCastToOperator(t, typeof(string))); Assert.Null(MethodInfoEx.FindCastToOperator(t, typeof(decimal))); }
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); }
public void FindCastWorks() { var t1 = typeof(Cast1); var t2 = typeof(Cast2); Assert.Equal(typeof(int), MethodInfoEx.FindCastOperator(t1, typeof(int)).ReturnType); Assert.Equal(typeof(double), MethodInfoEx.FindCastOperator(t1, typeof(double)).ReturnType); Assert.Null(MethodInfoEx.FindCastToOperator(t1, typeof(string))); Assert.Null(MethodInfoEx.FindCastToOperator(t1, typeof(decimal))); Assert.Equal(typeof(int), MethodInfoEx.FindCastOperator(typeof(int), t2).GetParameterTypes()[0]); Assert.Equal(typeof(double), MethodInfoEx.FindCastOperator(typeof(double), t2).GetParameterTypes()[0]); Assert.Equal(t2, MethodInfoEx.FindCastOperator(t2, t1).GetParameterTypes()[0]); Assert.Null(MethodInfoEx.FindCastOperator(typeof(string), t2)); Assert.Null(MethodInfoEx.FindCastOperator(typeof(decimal), t2)); Assert.Throws <AmbiguousMatchException>(() => MethodInfoEx.FindCastOperator(t1, t2)); }
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)); }
protected static MethodInfo FindMethodInfo(InvokeContextBase context) { if (context != null && !string.IsNullOrEmpty(context.TypeName) && !string.IsNullOrEmpty(context.MethodName)) { Type type = ActivatorEx.GetType(context.TypeName); if (type == null) { return(null); } MethodInfoCollection methods = GetMethodCollectionAndCache(context, type); if (methods != null && methods.Count > 0) { if (methods.Count == 1) { return(CreateMethodEx(methods[0])); } object[] args = context.Arguments; if (args == null) { args = _emptyArgs; context.Arguments = args; } int len = args.Length; Type[] argTypes = context.ArgumentTypes; bool selectedTypes = true; if (argTypes == null) { selectedTypes = false; argTypes = new Type[len]; for (int i = 0; i < len; i++) { if (args[i] != null) { argTypes[i] = args[i].GetType(); } } } BindingFlags binding = _defaultBinding; ArrayList list = new ArrayList(methods.Count); for (int i = 0; i < methods.Count; i++) { if (FilterApplyMethodBaseInfo(methods[i], binding, CallingConventions.Any, argTypes)) { list.Add(methods[i]); } } len = list.Count; if (len >= 1) { MethodInfoEx info = null; if (len == 1) { info = CreateMethodEx(list[0] as MethodInfo); } else { Binder binder = Type.DefaultBinder; MethodBase methodBase = null; MethodBase[] array = new MethodBase[len]; list.CopyTo(array); try { if (!selectedTypes) { object state; methodBase = binder.BindToMethod(binding, array, ref args, null, null, null, out state); } else { methodBase = binder.SelectMethod(binding, array, argTypes, null); } } catch (MissingMethodException) { methodBase = null; } if (methodBase != null) { info = CreateMethodEx(methodBase as MethodInfo); } } return(info); } } } return(null); }
/// <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)); }