1

我目前正在开发基于 WCF 数据服务工具包库的 OData API。

当 Lambda 表达式有许多运算符时,就会发生我当前的问题。

根据我的实验,当表达式的运算符超过 356 个时会发生 StackOverflowException。

以下语句是发生错误的地方。

return orderByMethod.Invoke(enumerable, new object[] { enumerable, operand.Compile() });

以下代码是整个代码。

    /// <summary>
    /// Executes a Linq2Objects expression to a given <see cref="IEnumerable" /> object.
    /// </summary>
    /// <param name="methodName">A string that indicates the name of the method.</param>
    /// <param name="enumerable">An <see cref="IEnumerable" /> object that will be filtered.</param>
    /// <param name="expression">An <see cref="Expression" /> to be applied to the <see cref="IEnumerable" /> object.</param>
    /// <returns>A filtered <see cref="IEnumerable" /> object.</returns>
    public static object ExecuteLinq2ObjectsImplementation(string methodName, IEnumerable<object> enumerable, Expression expression)
    {
        var orderByClause = expression as UnaryExpression;
        var operand = null == orderByClause ? expression as LambdaExpression : orderByClause.Operand as LambdaExpression;

        // The following conditional statement is added to avoid the stack overflow exception.
        int operatorNumber = (operand.ToString().Split('"').Length - 1) / 2;

        // The number is evaluated by executing vary queries. It means that dimension members can be selected up to 356 in a dimension.
        const int maximumOperatorNumber = 356;
        if (operatorNumber <= maximumOperatorNumber)
        {

            var whereInfo = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(mi => mi.Name == methodName && mi.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2);

            var currentType = enumerable.GetType();
            var seedElementType = currentType.IsArray ? currentType.GetElementType() : currentType.GetGenericArguments().ElementAt(0);

            var genericArguments = new List<Type> { seedElementType };

            if (whereInfo.GetGenericArguments().Count() > 1)
            {
                genericArguments.Add(operand.Body.Type);
            }

            var orderByMethod = whereInfo.MakeGenericMethod(genericArguments.ToArray());
            return orderByMethod.Invoke(enumerable, new object[] { enumerable, operand.Compile() });
        }

        else
        {
            throw new StackOverflowException("The OData query is too long.");
        }
    }

你对此有什么想法吗?

更新...

这是我为可能遇到相同问题的人提供的解决方案。

    /// <summary>
    /// Executes a Linq2Objects expression to a given <see cref="IEnumerable" /> object.
    /// </summary>
    /// <param name="methodName">A string that indicates the name of the method.</param>
    /// <param name="enumerable">An <see cref="IEnumerable" /> object that will be filtered.</param>
    /// <param name="expression">An <see cref="Expression" /> to be applied to the <see cref="IEnumerable" /> object.</param>
    /// <returns>A filtered <see cref="IEnumerable" /> object.</returns>
    public static object ExecuteLinq2ObjectsImplementation(string methodName, IEnumerable<object> enumerable, Expression expression)
    {
        var orderByClause = expression as UnaryExpression;
        var operand = null == orderByClause ? expression as LambdaExpression : orderByClause.Operand as LambdaExpression;

        var whereInfo = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public).First(mi => mi.Name == methodName && mi.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2);

        var currentType = enumerable.GetType();
        var seedElementType = currentType.IsArray ? currentType.GetElementType() : currentType.GetGenericArguments().ElementAt(0);

        var genericArguments = new List<Type> { seedElementType };

        if (whereInfo.GetGenericArguments().Count() > 1)
        {
            genericArguments.Add(operand.Body.Type);
        }

        // The following conditional statement is added to avoid the stack overflow exception.
        int operatorNumber = (operand.ToString().Split('"').Length - 1) / 2;

        // If the number of selected members in a dimension is equal or less than 356, then the data will be sorted based on the current dimmension with the $orderby query.
        // Otherwise, the method will not perform sorting to avoid StackOverflowException.
        // For your guidance the number is evaluated by executing vary queries.
        const int maximumOperatorNumber = 356;
        if (operatorNumber <= maximumOperatorNumber)
        {
            var orderByMethod = whereInfo.MakeGenericMethod(genericArguments.ToArray());
            return orderByMethod.Invoke(null, new object[] { enumerable, operand.Compile() });
        }

        else {
            return enumerable;
        }
    }
4

1 回答 1

0

我认为您的代码没有任何问题。发生此错误与有限的内存有关。

请查看给定的链接:

http://www.dotnetperls.com/stackoverflowexception

谢谢, HItesh

于 2013-06-18T05:50:20.370 回答