Beispiel #1
0
        /// <summary>
        /// Visit a member access expression
        /// </summary>
        /// <param name="exp"></param>
        /// <returns></returns>
        protected EToken VisitMemberAccessExpression(MemberExpression exp)
        {
            EToken memberExp;

            if (exp.Expression == null)
            {
                // Método estáticos
                // TODO: El tipo ExpressionType.Unbox aquí es incorrecto, debería ser null
                memberExp = new EToken(exp.Type.FullName, ExpressionType.Unbox, null);
            }
            else
            {
                // Métodos en objetos
                memberExp = this.VisitExpression(exp.Expression, exp);
            }

            var memberName = exp.Member.Name;
            var memberType = this.GetUnderlyingType(exp.Member);

            if (memberExp.Type == ExpressionType.Constant)
            {
                // Nos permite evaluar sobre la marcha member accesors que SÍ podemos resolver
                if (memberExp.ClrType.IsNullable() && memberName == "Value")
                {
                    // No hacer nada, ya que la llamada a Value() - que es un unboxing de un struct -
                    // lo hace automáticamente el runtime de .Net
                }
                else
                {
                    this.Arguments[memberExp.Text] = Dynamic.InvokeGet(this.Arguments[memberExp.Text], memberName);
                }

                return(new EToken(memberExp.Text, ExpressionType.Constant, memberType));
            }

            if (memberExp.Type == ExpressionType.Unbox)
            {
                var expCallResult = ((FieldInfo)exp.Member).GetValue(null);
                return(new EToken(this.AddArgument(expCallResult), ExpressionType.Constant, memberType));
            }

            return(new EToken($"{memberExp.Text}.{memberName}", exp.NodeType, memberType));
        }
Beispiel #2
0
        /// <summary>
        /// Visit a method call expression
        /// </summary>
        /// <param name="expCall"></param>
        /// <returns></returns>
        protected EToken VisitMethodCallExpression(MethodCallExpression expCall)
        {
            List <EToken> args = (from p in expCall.Arguments
                                  select this.VisitExpression(p, expCall)).ToList();

            EToken expCallTargetExpression;

            if (expCall.Object == null)
            {
                // Here we should use FullName of declaring type, but a bug in Dynamic.Linq.Core prevents
                // usage of full namespaces and uses shortcut aliases only.
                // TODO: El tipo ExpressionType.Unbox aquí es incorrecto, debería ser null
                expCallTargetExpression = new EToken(expCall.Method?.DeclaringType?.Name, ExpressionType.Unbox, null);
            }
            else
            {
                // Métodos en objetos
                expCallTargetExpression = this.VisitExpression(expCall.Object, expCall);
            }

            bool canMaterializeMethodCall = args.All((i) => i.Type == ExpressionType.Constant) &&
                                            (expCallTargetExpression.Type == ExpressionType.Constant ||
                                             expCallTargetExpression.Type == ExpressionType.Unbox);

            if (canMaterializeMethodCall)
            {
                List <object> methodCallUnboxedArgs = new List <object>();

                // Grab all arguments and remove them from the dictionary
                foreach (var arg in args)
                {
                    methodCallUnboxedArgs.Add(this.PopArgument(arg.Text));
                }

                object expCallResult;

                if (expCall.Object == null)
                {
                    expCallResult = Dynamic.InvokeMember(
                        InvokeContext.CreateStatic(expCall.Method?.DeclaringType),
                        expCall.Method.Name,
                        methodCallUnboxedArgs.ToArray());
                }
                else
                {
                    expCallResult = Dynamic.InvokeMember(
                        this.PopArgument(expCallTargetExpression.Text),
                        expCall.Method.Name,
                        methodCallUnboxedArgs.ToArray());
                }

                return(this.CheckMaterializationResult(expCallResult, expCall.Method.ReturnType));
            }

            // If this method is LinqKit's Invoke() then we can do this ASAP because Dynamic.Linq.Core won't swallow complex method calls
            // We asume that the coder is looking for lazy evaluation
            if (expCall.Method.Name == "Invoke" && expCall.Method?.DeclaringType?.FullName.Contains("LinqKit") == true)
            {
                var targetOfInvoke = expCall.Arguments.First() as MethodCallExpression;

                var argumentsOfTargetInvoke = new List <object>();
                foreach (var arg in targetOfInvoke.Arguments)
                {
                    if (arg is ConstantExpression constant)
                    {
                        argumentsOfTargetInvoke.Add(constant.Value);
                    }
                }

                // Materialize it! Currently only works with static calls
                var materializedTargetOfInvoke = Dynamic.InvokeMember(
                    InvokeContext.CreateStatic(targetOfInvoke.Method?.DeclaringType),
                    targetOfInvoke.Method.Name,
                    argumentsOfTargetInvoke.ToArray()) as LambdaExpression;

                var result = this.VisitLambdaExpression(materializedTargetOfInvoke);

                // Replace the target source arguments
                for (int x = 0; x < materializedTargetOfInvoke.Parameters.Count; x++)
                {
                    var expArg      = materializedTargetOfInvoke.Parameters[x];
                    var externalArg = args[x + 1];

                    this.Parameters.Remove(expArg.Name);
                    this.TempParameters.Remove(expArg.Name);
                    result.Text = result.Text.Replace($"[{expArg.Name}]", externalArg.Text);
                }

                return(result);
            }

            return(new EToken($"{expCallTargetExpression}.{expCall.Method.Name}({args.StringJoinObject(", ")})", expCall.NodeType, expCall.Method.ReturnType));
        }