2013-02-18 2 views
2

CA1006 : DoNotNestGenericTypesInMemberSignatures 규칙을 위반하는 다음 멤버를 구현하는 확장 클래스를 얻었습니다.구성원 서명에 제네릭 형식을 중첩시키지 마십시오.

경고가 참조하는 코드는 다음과 같습니다.

CA1006 경고를 해결하기 위해 코드를 어떻게 리팩터링해야합니까?

익명 메서드, 대리자 및 람다에 대해 잘 알고 있지만 식 트리에 익숙하지 않습니다.

도움이 될 것입니다.

public static DataServiceQuery<TElement> Expand<TElement, TPropType>(this DataServiceQuery<TElement> source, Expression<Func<TElement, TPropType>> propertySelector) 
    { 
     string includeString = BuildString(propertySelector); 
     return source.Expand(includeString); 
    } 

    private static string BuildString(Expression propertySelector) 
    { 
     switch (propertySelector.NodeType) 
     { 
      case ExpressionType.Lambda: 
       LambdaExpression lambdaExpression = (LambdaExpression)propertySelector; 
       return BuildString(lambdaExpression.Body); 

      case ExpressionType.Quote: 
       UnaryExpression unaryExpression = (UnaryExpression)propertySelector; 
       return BuildString(unaryExpression.Operand); 

      case ExpressionType.MemberAccess: 

       MemberExpression memberExpression = (MemberExpression)propertySelector; 
       MemberInfo propertyInfo = memberExpression.Member; 

       if (memberExpression.Expression is ParameterExpression) 
       { 
        return propertyInfo.Name; 
       } 
       else 
       { 
        // we've got a nested property (e.g. MyType.SomeProperty.SomeNestedProperty) 
        return BuildString(memberExpression.Expression) + "/" + propertyInfo.Name; 
       } 

      case ExpressionType.Call: 
       MethodCallExpression methodCallExpression = (MethodCallExpression)propertySelector; 
       if (IsSubInclude(methodCallExpression.Method)) // check that it's a SubInclude call 
       { 
        // argument 0 is the expression to which the SubInclude is applied (this could be member access or another SubInclude) 
        // argument 1 is the expression to apply to get the included property 
        // Pass both to BuildString to get the full expression 
        return BuildString(methodCallExpression.Arguments[0]) + "/" + 
          BuildString(methodCallExpression.Arguments[1]); 
       } 
       // else drop out and throw 
       break; 
     } 
     throw new InvalidOperationException("Expression must be a member expression or an SubInclude call: " + propertySelector.ToString()); 

    } 

    private static readonly MethodInfo[] SubIncludeMethods; 
    static MyExtensions() 
    { 
     Type type = typeof(MyExtensions); 
     SubIncludeMethods = type.GetMethods().Where(mi => mi.Name == "SubExpand").ToArray(); 
    } 

    private static bool IsSubInclude(MethodInfo methodInfo) 
    { 
     if (methodInfo.IsGenericMethod) 
     { 
      if (!methodInfo.IsGenericMethodDefinition) 
      { 
       methodInfo = methodInfo.GetGenericMethodDefinition(); 
      } 
     } 
     return SubIncludeMethods.Contains(methodInfo); 
    } 

    public static TPropType SubExpand<TSource, TPropType>(this Collection<TSource> source, Expression<Func<TSource, TPropType>> propertySelector) 
     where TSource : class 
     where TPropType : class 
    { 
     throw new InvalidOperationException("This method is only intended for use with DataServiceQueryExtensions.Expand to generate expressions trees"); // no actually using this - just want the expression! 
    } 

    public static TPropType SubExpand<TSource, TPropType>(this TSource source, Expression<Func<TSource, TPropType>> propertySelector) 
     where TSource : class 
     where TPropType : class 
    { 
     throw new InvalidOperationException("This method is only intended for use with DataServiceQueryExtensions.Expand to generate expressions trees"); // no actually using this - just want the expression! 
    } 
+0

는이 코드의 예를 제공 할 수 있습니다 사용중인? 그것은 꽤 복잡하고 결함이 어디에 있는지 알기가 다소 까다 롭습니다 – DiskJunky

+0

public 메소드의 propertySelector 매개 변수를 언급하고 있습니까? 이 경고는 메서드에 대한 인터페이스를 사용할 수 있도록하는 것에 관한 것입니다. 그러나 Expression에서는 속성 또는 메서드 호출에서 반환 값으로 제공하는 클래스에서 expression 매개 변수를 래핑하지 않는 한 리팩토링되지 않습니다. – Jay

+1

DiskJunky,이 문제를 해결하는 데 관심을 가져 주셔서 감사합니다. 본질적으로 코드는 다음과 같이 람다 식을 작성하는 데 사용됩니다. var scenarioGroups = ctx.ScenarioGroups.Expand의 scenarioGroup (scenarioGroup => scenarioGroup.Scenarios.SubExpand (sc => sc.XYLines.SubExpand (xy => xy.Points))) 여기서 ... –

답변

7

경고는보다 단순하고 공개 된 인터페이스를 설계하는 데 도움이되는 일반적인 경고입니다. 이 경우 메서드에 Expression<Func<TElement, TPropType>> 매개 변수가 있음에 대한 경고 메시지가 나타납니다. 그러나이 방법을 사용하면 유형을 단순화 할 필요가 없으므로 attribute을 사용하여 경고를 억제하거나 규칙 집합에서 규칙을 완전히 제거해야합니다.


당신은 아마이 같은 방법 규칙의 조언되어 다음 사항을 고려한다 바보 예 :

public void F(Dictionary<String, List<Tuple<String, Int32>>> dictionary); 
+0

마틴 도움에 감사드립니다. 나는 네가 옳다고 믿는다. 유형을 시도하고 단순화하는 것이 무의미하다는 것이 분명 해졌다. 대신에 그것을 억제해야 할 것입니다. –

+2

잠시 동안이 경고를 지킨 후에 나는 너무 많은 소음을 일으키기 때문에 그것을 억압했다. "depth"가 1 (T >) 인 중첩 제네릭 형식의 사용이 합법적이었던 시간의 99 %를 발견했습니다. 규칙이 시작 깊이 2 (T >>)에 대해서만 트리거되도록 정교화되기를 기다리는 것이 훨씬 의미가 있습니다.) – darkey