2013-06-18 2 views
1

현재 WCF Data Service Toolkit 라이브러리를 기반으로 OData API를 개발하고 있습니다.MakeGenericMethod 클래스의 Invoke 메서드를 호출 할 때 StackOverflowException이 발생했습니다.

현재 람다식이 많은 연산자를 사용하면 현재 문제가 발생합니다.

표현식에 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; 
     } 
    } 
+0

첫 번째 문제는 : 당신은 정적 메소드에 null 이외의 대상을 통과 한 것으로 나타났습니다. 'Invoke'의 첫번째 인자는'null'이어야합니다. 나는 그것이 차이를 만들지 않을 것이라고 생각하지만, 내가 당신이라면 여전히 고칠 것입니다. –

+0

@ 존 쉘스 나는 당신과 동의하지 않습니다. MSDN에 따르면 null이거나 생성자를 정의하는 클래스의 인스턴스 일 수 있습니다. http://msdn.microsoft.com/en-us/library/a89hcwhh.aspx 첫 번째 인수를 null로 변경하면 잘 작동합니다. 그러나 여전히 동일한 오류가 있습니다. – user2495856

+0

@ user2495856 문서에서 실제로 static * method * (있는 그대로)를 호출하는 경우 첫 번째 매개 변수는 똑바로 무시됩니다. – dlev

답변

0

코드에 문제가없는 것으로 생각됩니다. 제한된 메모리와 관련하여이 오류가 발생했습니다.

주어진 링크를보고하십시오 :

http://www.dotnetperls.com/stackoverflowexception

감사합니다, HItesh

+0

그 기사를 읽었지 만 공유해 주셔서 감사합니다. 어떻게 한계를 극복 할 수 있습니까? – user2495856

관련 문제