Пример #1
0
        public static bool TryEmit(this Expression expression, out Delegate resultDelegate, Type delegateType,
                                   Type returnType, params ParameterExpression[] parameters)
        {
            resultDelegate = null;

            var analyzer = new TreeAnalyzer();

            if (!analyzer.Analyze(expression, parameters))
            {
                return(false);
            }

            var capturedArgumentsType = analyzer.CapturedParameters.Length > 0 ? DynamicModule.GetOrAddCapturedArgumentsType(analyzer.CapturedParameters) : null;

            if (analyzer.NestedLambdas.Length > 0)
            {
                PrepareNestedLambdaTypes(analyzer, capturedArgumentsType);
            }

            var targetType = analyzer.StoredExpressions.Length > 0 ? DynamicModule.GetOrAddTargetType(analyzer.StoredObjectTypes) : null;

            var delegateTarget = targetType != null
                ? new DelegateTarget(targetType.GetTypeInfo().DeclaredFields.CastToArray(), targetType, Activator.CreateInstance(targetType, analyzer.StoredObjects))
                : null;

            var capturedArgumentsHolder = capturedArgumentsType != null
                ? new CapturedArgumentsHolder(capturedArgumentsType.GetTypeInfo().DeclaredFields.CastToArray(), capturedArgumentsType)
                : null;

            var context = new CompilerContext(delegateTarget, analyzer.DefinedVariables, analyzer.StoredExpressions,
                                              analyzer.CapturedParameters, analyzer.NestedLambdas, capturedArgumentsHolder);

            var method    = Emitter.CreateDynamicMethod(context, returnType, parameters);
            var generator = method.GetILGenerator();

            if (context.HasCapturedVariablesArgument)
            {
                context.CapturedArgumentsHolderVariable = generator.PrepareCapturedArgumentsHolderVariable(capturedArgumentsType);
                generator.CopyParametersToCapturedArgumentsIfAny(context, parameters);
            }

            if (analyzer.DefinedVariables.Length > 0)
            {
                context.LocalBuilders = Emitter.BuildLocals(analyzer.DefinedVariables, generator);
            }

            if (!expression.TryEmit(generator, context, parameters))
            {
                return(false);
            }

            generator.Emit(OpCodes.Ret);

            resultDelegate = context.HasClosure
                ? method.CreateDelegate(delegateType, context.Target.Target)
                : method.CreateDelegate(delegateType);

            return(true);
        }
Пример #2
0
        public bool Analyze(Expression expression, params ParameterExpression[] parameters)
        {
            switch (expression.NodeType)
            {
            case ExpressionType.Parameter:

                if (parameters.ContainsElement(expression) || this.DefinedVariables.ContainsElement(expression))
                {
                    return(true);
                }
                this.AddCapturedParameter((ParameterExpression)expression);
                return(true);

            case ExpressionType.Lambda:
                var lambda = (LambdaExpression)expression;

                var analyzer = new TreeAnalyzer();
                if (!analyzer.Analyze(lambda.Body, lambda.Parameters.CastToArray()))
                {
                    return(false);
                }

                this.AddNestedLambda(new KeyValue <LambdaExpression, Expression[]>(lambda, analyzer.DefinedVariables));

                var length = analyzer.StoredExpressions.Length;
                for (var i = 0; i < length; i++)
                {
                    this.AddStoredItem(analyzer.StoredExpressions[i], analyzer.StoredExpressions[i].Type, analyzer.StoredObjects[i]);
                }

                var lambdaLength = analyzer.NestedLambdas.Length;
                for (var i = 0; i < lambdaLength; i++)
                {
                    this.AddNestedLambda(analyzer.NestedLambdas[i]);
                }

                var capturedLength = analyzer.CapturedParameters.Length;
                for (var i = 0; i < capturedLength; i++)
                {
                    this.AddCapturedParameter(analyzer.CapturedParameters[i]);
                }

                return(true);

            case ExpressionType.MemberAccess:
                return(this.Analyze(((MemberExpression)expression).Expression, parameters));

            case ExpressionType.Constant:
                var constant = (ConstantExpression)expression;
                if (constant.Value == null || IsInPlaceEmittableConstant(constant.Type, constant.Value))
                {
                    return(true);
                }
                this.AddStoredItem(constant, constant.Type, constant.Value);
                return(true);

            case ExpressionType.New:
                return(this.Analyze(((NewExpression)expression).Arguments, parameters));

            case ExpressionType.MemberInit:
                var memberInit = (MemberInitExpression)expression;
                if (!this.Analyze(memberInit.NewExpression, parameters))
                {
                    return(false);
                }

                return(this.Analyze(memberInit.Bindings, parameters));

            case ExpressionType.Block:
                var block = (BlockExpression)expression;
                for (var i = 0; i < block.Variables.Count; i++)
                {
                    this.AddDefinedVariable(block.Variables[i]);
                }

                return(this.Analyze(block.Expressions, parameters));

            case ExpressionType.Conditional:
                var condition = (ConditionalExpression)expression;
                return(this.Analyze(condition.Test, parameters) &&
                       this.Analyze(condition.IfTrue, parameters) &&
                       this.Analyze(condition.IfFalse, parameters));

            case ExpressionType.Default:
                return(true);

            case ExpressionType.Call:
                var call = (MethodCallExpression)expression;
                return((call.Object == null || this.Analyze(call.Object, parameters)) &&
                       this.Analyze(call.Arguments, parameters));

            case ExpressionType.Invoke:
                var invoke = (InvocationExpression)expression;
                return(this.Analyze(invoke.Expression, parameters) &&
                       this.Analyze(invoke.Arguments, parameters));

            case ExpressionType.NewArrayInit:
                return(this.Analyze(((NewArrayExpression)expression).Expressions, parameters));

            default:
                if (expression is UnaryExpression unaryExpression)
                {
                    return(this.Analyze(unaryExpression.Operand, parameters));
                }

                if (expression is BinaryExpression binaryExpression)
                {
                    return(this.Analyze(binaryExpression.Left, parameters) &&
                           this.Analyze(binaryExpression.Right, parameters));
                }

                break;
            }

            return(false);
        }