Exemplo n.º 1
0
        private static void UnpackImpl(LambdaExpression expression, Type voidType, out Expression body, out IEnumerable <ParameterExpression> parameters)
        {
            var count = expression.Parameters.Count;

            if (count == 0)
            {
                body       = expression.Body;
                parameters = expression.Parameters;
                return;
            }

            if (count != 1)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Expression '{0}' has more than one parameter. In order to detupletize a lambda expression, it should have exactly one parameter of a tuple type.", expression));
            }

            var tupleParameter = expression.Parameters[0];
            var parameterType  = tupleParameter.Type;

            if (parameterType == voidType)
            {
#if USE_SLIM
                if (FreeVariableScanner.Find(expression.Body).Contains(tupleParameter))
#else
                if (FreeVariableScanner.Scan(expression.Body).Contains(tupleParameter))
#endif
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The 'void' parameter is bound in the body of lambda expression '{0}'. In order to detupletize a lambda expression with a 'void' parameter, the parameter should be unbound.", expression));
                }

                body       = expression.Body;
                parameters = Array.Empty <ParameterExpression>();
                return;
            }

            if (!IsTuple(parameterType))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The type of parameter '{0}' in '{1}' is not a valid tuple type: '{2}'.", tupleParameter, expression, parameterType));
            }

            var tupleType = tupleParameter.Type;

            var newParameters = new List <ParameterExpression>();

            const int max = TupleTypeCount - 1 /* T1..T7,TRest */;

            var type = tupleType;

            var i = 0;
            while (true)
            {
                var args = type.GetGenericArguments();

                var n = args.Length;

                if (args.Length == max)
                {
                    n--;
                }

                for (var j = 0; j < n; j++)
                {
                    var arg = args[j];
                    newParameters.Add(Expression.Parameter(arg, "p" + i++));
                }

                if (args.Length == max)
                {
                    type = args.Last();
                }
                else
                {
                    break;
                }
            }

            var subst = new ParameterBasedDetupletizer(tupleParameter, newParameters);

            body       = subst.Visit(expression.Body);
            parameters = newParameters;
        }