private static object TryCompile(ref ClosureInfo closureInfo, Type delegateType, Type[] paramTypes, Type returnType, Expression bodyExpr, IList <ParameterExpression> paramExprs) { if (!TryCollectBoundConstants(ref closureInfo, bodyExpr, paramExprs)) { return(null); } if (closureInfo != null) { closureInfo.ConstructClosure(); } var method = GetDynamicMethod(paramTypes, returnType, closureInfo); var il = method.GetILGenerator(); if (!EmittingVisitor.TryEmit(bodyExpr, paramExprs, il, closureInfo)) { return(null); } il.Emit(OpCodes.Ret); // emits return from generated method // create open delegate with closure object if (closureInfo == null) { return(method.CreateDelegate(delegateType)); } return(method.CreateDelegate(delegateType, closureInfo.ClosureObject)); }
/// <summary>Compiles expression to delegate by emitting the IL. /// If sub-expressions are not supported by emitter, then the method returns null. /// The usage should be calling the method, if result is null then calling the Expression.Compile.</summary> /// <param name="bodyExpr">Lambda body.</param> /// <param name="paramExprs">Lambda parameter expressions.</param> /// <param name="paramTypes">The types of parameters.</param> /// <param name="returnType">The return type.</param> /// <returns>Result delegate or null, if unable to compile.</returns> public static TDelegate TryCompile <TDelegate>( Expression bodyExpr, ParameterExpression[] paramExprs, Type[] paramTypes, Type returnType) where TDelegate : class { var constantExprs = new List <ConstantExpression>(); if (!TryCollectBoundConstants(bodyExpr, constantExprs)) { return(null); } object closure = null; ClosureInfo closureInfo = null; DynamicMethod method; if (constantExprs.Count == 0) { method = new DynamicMethod(string.Empty, returnType, paramTypes, typeof(FastExpressionCompiler).Module, skipVisibility: true); } else { var constants = new object[constantExprs.Count]; var constantCount = constants.Length; for (var i = constantCount - 1; i >= 0; i--) { constants[i] = constantExprs[i].Value; } if (constantCount <= Closure.CreateMethods.Length) { var createClosureMethod = Closure.CreateMethods[constantCount - 1]; var constantTypes = new Type[constantCount]; for (var i = 0; i < constantCount; i++) { constantTypes[i] = constantExprs[i].Type; } var createClosure = createClosureMethod.MakeGenericMethod(constantTypes); closure = createClosure.Invoke(null, constants); var fields = closure.GetType().GetTypeInfo().DeclaredFields; var fieldsArray = fields as FieldInfo[] ?? fields.ToArray(); closureInfo = new ClosureInfo(constantExprs, fieldsArray); } else { var arrayClosure = new ArrayClosure(constants); closure = arrayClosure; closureInfo = new ClosureInfo(constantExprs); } var closureType = closure.GetType(); var closureAndParamTypes = GetClosureAndParamTypes(paramTypes, closureType); method = new DynamicMethod(string.Empty, returnType, closureAndParamTypes, closureType, skipVisibility: true); } var il = method.GetILGenerator(); var emitted = EmittingVisitor.TryEmit(bodyExpr, paramExprs, il, closureInfo); if (emitted) { il.Emit(OpCodes.Ret); return((TDelegate)(object)method.CreateDelegate(typeof(TDelegate), closure)); } return(null); }